about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml7
-rw-r--r--.gitmodules11
-rw-r--r--Cargo.lock50
-rw-r--r--compiler/rustc/build.rs2
-rw-r--r--compiler/rustc_abi/src/layout.rs8
-rw-r--r--compiler/rustc_abi/src/lib.rs19
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs101
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs9
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs3
-rw-r--r--compiler/rustc_borrowck/src/lib.rs17
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs14
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs143
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs64
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs52
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs50
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs36
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs54
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs87
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs291
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs27
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs39
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs29
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs46
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs333
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs78
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs33
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs39
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs29
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs8
-rw-r--r--compiler/rustc_data_structures/src/base_n.rs7
-rw-r--r--compiler/rustc_data_structures/src/binary_search_util/mod.rs38
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs5
-rw-r--r--compiler/rustc_data_structures/src/sync/vec.rs28
-rw-r--r--compiler/rustc_data_structures/src/sync/worker_local.rs2
-rw-r--r--compiler/rustc_error_messages/src/lib.rs10
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs20
-rw-r--r--compiler/rustc_errors/src/emitter.rs14
-rw-r--r--compiler/rustc_errors/src/json.rs8
-rw-r--r--compiler/rustc_errors/src/lib.rs8
-rw-r--r--compiler/rustc_expand/src/config.rs6
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs41
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs2
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs106
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs167
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs2
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs10
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs8
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs16
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs55
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs19
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs4
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs7
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs8
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs6
-rw-r--r--compiler/rustc_infer/src/traits/project.rs8
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs10
-rw-r--r--compiler/rustc_lexer/Cargo.toml6
-rw-r--r--compiler/rustc_lexer/src/lib.rs11
-rw-r--r--compiler/rustc_lint/src/builtin.rs19
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp54
-rw-r--r--compiler/rustc_log/src/lib.rs2
-rw-r--r--compiler/rustc_macros/src/serialize.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs3
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs2
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/lint.rs14
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs14
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs120
-rw-r--r--compiler/rustc_middle/src/mir/generic_graph.rs4
-rw-r--r--compiler/rustc_middle/src/mir/generic_graphviz.rs10
-rw-r--r--compiler/rustc_middle/src/mir/graphviz.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs6
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs12
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs128
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs8
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs89
-rw-r--r--compiler/rustc_middle/src/mir/query.rs2
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs17
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs26
-rw-r--r--compiler/rustc_middle/src/query/mod.rs9
-rw-r--r--compiler/rustc_middle/src/thir.rs22
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs39
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs3
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs4
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs4
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs18
-rw-r--r--compiler/rustc_middle/src/ty/error.rs8
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs16
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs29
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs16
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs41
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs18
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs4
-rw-r--r--compiler/rustc_middle/src/util/bug.rs2
-rw-r--r--compiler/rustc_middle/src/util/common.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs55
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs27
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs57
-rw-r--r--compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs4
-rw-r--r--compiler/rustc_parse/messages.ftl4
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/lexer/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs15
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs17
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs51
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs97
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs6
-rw-r--r--compiler/rustc_parse/src/parser/path.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs9
-rw-r--r--compiler/rustc_privacy/src/lib.rs6
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs4
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs60
-rw-r--r--compiler/rustc_resolve/src/ident.rs6
-rw-r--r--compiler/rustc_resolve/src/imports.rs68
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs62
-rw-r--r--compiler/rustc_resolve/src/lib.rs4
-rw-r--r--compiler/rustc_resolve/src/macros.rs6
-rw-r--r--compiler/rustc_session/src/config.rs8
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs248
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/body.rs142
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/riscv64_linux_android.rs19
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs27
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs444
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs152
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs6
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs86
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs1
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs10
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--config.example.toml8
-rw-r--r--library/alloc/src/collections/btree/map.rs8
-rw-r--r--library/alloc/src/collections/btree/set.rs13
-rw-r--r--library/alloc/src/rc.rs2
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/mod.rs2
-rw-r--r--library/alloc/tests/string.rs48
-rw-r--r--library/core/src/cell/once.rs8
-rw-r--r--library/core/src/error.md6
-rw-r--r--library/core/src/fmt/mod.rs20
-rw-r--r--library/core/src/option.rs1
-rw-r--r--library/core/src/panic/panic_info.rs10
-rw-r--r--library/core/src/ptr/non_null.rs5
-rw-r--r--library/core/src/result.rs1
-rw-r--r--library/core/src/slice/index.rs6
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/src/str/mod.rs11
-rw-r--r--library/core/src/str/traits.rs52
-rw-r--r--library/portable-simd/crates/core_simd/examples/dot_product.rs2
-rw-r--r--library/std/src/backtrace.rs59
-rw-r--r--library/std/src/backtrace/tests.rs13
-rw-r--r--library/std/src/error.rs3
-rw-r--r--library/std/src/ffi/mod.rs2
-rw-r--r--library/std/src/io/util.rs100
-rw-r--r--library/std/src/io/util/tests.rs13
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/android/raw.rs2
-rw-r--r--library/std/src/panicking.rs2
-rw-r--r--library/std/src/sync/condvar.rs18
-rw-r--r--library/std/src/sync/lazy_lock.rs17
-rw-r--r--library/std/src/sync/mutex.rs8
-rw-r--r--library/std/src/sync/once_lock.rs8
-rw-r--r--library/std/src/sync/rwlock.rs8
-rw-r--r--library/std/src/sys_common/backtrace.rs19
-rw-r--r--library/test/src/types.rs2
-rw-r--r--src/bootstrap/bin/main.rs8
-rw-r--r--src/bootstrap/bin/rustc.rs23
-rw-r--r--src/bootstrap/bin/rustdoc.rs8
-rw-r--r--src/bootstrap/bolt.rs62
-rw-r--r--src/bootstrap/build.rs2
-rw-r--r--src/bootstrap/builder.rs39
-rw-r--r--src/bootstrap/cache.rs4
-rw-r--r--src/bootstrap/cc_detect.rs2
-rw-r--r--src/bootstrap/check.rs4
-rw-r--r--src/bootstrap/clean.rs84
-rw-r--r--src/bootstrap/compile.rs29
-rw-r--r--src/bootstrap/config.rs47
-rw-r--r--src/bootstrap/dist.rs145
-rw-r--r--src/bootstrap/doc.rs6
-rw-r--r--src/bootstrap/download.rs8
-rw-r--r--src/bootstrap/flags.rs13
-rw-r--r--src/bootstrap/format.rs8
-rw-r--r--src/bootstrap/lib.rs49
-rw-r--r--src/bootstrap/llvm.rs33
-rw-r--r--src/bootstrap/sanity.rs2
-rw-r--r--src/bootstrap/setup.rs14
-rw-r--r--src/bootstrap/tarball.rs4
-rw-r--r--src/bootstrap/test.rs8
-rw-r--r--src/bootstrap/toolstate.rs32
-rw-r--r--src/bootstrap/util.rs24
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile54
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile24
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh (renamed from src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh)0
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile20
-rw-r--r--src/ci/github-actions/ci.yml10
-rwxr-xr-xsrc/ci/scripts/install-clang.sh5
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md11
-rw-r--r--src/doc/style-guide/src/README.md10
-rw-r--r--src/doc/style-guide/src/SUMMARY.md1
-rw-r--r--src/doc/style-guide/src/advice.md20
-rw-r--r--src/doc/style-guide/src/editions.md46
-rw-r--r--src/doc/style-guide/src/expressions.md78
-rw-r--r--src/doc/style-guide/src/items.md73
-rw-r--r--src/doc/style-guide/src/nightly.md2
-rw-r--r--src/doc/style-guide/src/principles.md42
-rw-r--r--src/doc/style-guide/src/statements.md12
-rw-r--r--src/doc/style-guide/src/types.md33
-rw-r--r--src/doc/unstable-book/src/compiler-flags/no-parallel-llvm.md8
-rw-r--r--src/etc/completions/x.py.fish49
-rw-r--r--src/etc/completions/x.py.ps149
-rw-r--r--src/etc/completions/x.py.sh68
-rw-r--r--src/etc/rust_analyzer_settings.json5
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/clean/utils.rs34
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/markdown/tests.rs2
-rw-r--r--src/librustdoc/html/render/context.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs179
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/librustdoc/passes/stripper.rs2
-rw-r--r--src/librustdoc/visit_ast.rs30
-rw-r--r--src/tools/build-manifest/Cargo.toml2
-rw-r--r--src/tools/build_helper/src/git.rs38
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml29
-rw-r--r--src/tools/clippy/CHANGELOG.md14
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md21
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/absolute_paths.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1018
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs334
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/incorrect_impls.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs190
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs320
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/format_collect.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs220
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs205
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs316
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs25
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs282
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs198
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs122
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs320
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs49
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/src/main.rs3
-rw-r--r--src/tools/clippy/tests/compile-test.rs40
-rw-r--r--src/tools/clippy/tests/integration.rs24
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr28
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs97
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs11
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr4
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.rs30
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr6
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs7
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr40
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.rs90
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.stderr45
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed55
-rw-r--r--src/tools/clippy/tests/ui/eta.rs55
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr8
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.fixed44
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.rs44
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.stderr34
-rw-r--r--src/tools/clippy/tests/ui/format_collect.rs31
-rw-r--r--src/tools/clippy/tests/ui/format_collect.stderr62
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.fixed48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.rs48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.stderr68
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr15
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs41
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr20
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs4
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr4
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed33
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs33
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr4
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs51
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr31
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr16
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.rs26
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.stderr10
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.fixed25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.rs25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.stderr43
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.rs10
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_future.stderr16
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.fixed24
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.rs28
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.stderr73
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.stderr53
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr28
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.rs4
-rw-r--r--src/tools/clippy/tests/ui/mut_key.stderr16
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr24
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs120
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr72
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.rs40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr10
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr18
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr46
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed63
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs55
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr90
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs13
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs6
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.stderr20
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.rs42
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.stderr16
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed133
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs133
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.stderr98
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs111
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr136
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr74
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed2
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr114
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed123
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs3
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs7
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr92
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr18
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.fixed27
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.rs27
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr6
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed1
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr36
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs16
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr64
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.fixed50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.rs50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.stderr58
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed3
-rw-r--r--src/tools/clippy/tests/ui/swap.rs3
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr34
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed6
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs6
-rw-r--r--src/tools/clippy/tests/ui/try_err.stderr22
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.rs30
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.stderr36
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr88
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed11
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs11
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr188
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr182
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs17
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.fixed62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.rs62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.stderr100
-rw-r--r--src/tools/clippy/triagebot.toml5
-rw-r--r--src/tools/miri/.github/workflows/ci.yml13
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs15
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs87
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs243
-rw-r--r--src/tools/miri/src/mono_hash_map.rs2
-rw-r--r--src/tools/miri/src/shims/backtrace.rs10
-rw-r--r--src/tools/miri/src/shims/time.rs5
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs12
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs4
-rw-r--r--src/tools/miri/tests/compiletest.rs2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/concurrency/unwind_top_of_stack.stderr3
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr3
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr3
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr3
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr3
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/panic/bad_unwind.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/double_panic.stderr6
-rw-r--r--src/tools/miri/tests/fail/panic/no_std.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort1.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort2.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort3.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort4.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/thread_local_const_drop_panic.stderr3
-rw-r--r--src/tools/miri/tests/fail/panic/thread_local_drop_panic.stderr3
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.stderr3
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/outside-range.stderr4
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr8
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr8
-rw-r--r--src/tools/miri/tests/fail/unwind-action-terminate.stderr3
-rw-r--r--src/tools/miri/tests/panic/div-by-zero-2.stderr3
-rw-r--r--src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr9
-rw-r--r--src/tools/miri/tests/panic/oob_subslice.stderr3
-rw-r--r--src/tools/miri/tests/panic/overflowing-lsh-neg.stderr3
-rw-r--r--src/tools/miri/tests/panic/overflowing-rsh-1.stderr3
-rw-r--r--src/tools/miri/tests/panic/overflowing-rsh-2.stderr3
-rw-r--r--src/tools/miri/tests/panic/panic1.stderr3
-rw-r--r--src/tools/miri/tests/panic/panic2.stderr3
-rw-r--r--src/tools/miri/tests/panic/panic3.stderr3
-rw-r--r--src/tools/miri/tests/panic/panic4.stderr3
-rw-r--r--src/tools/miri/tests/panic/transmute_fat2.stderr3
-rw-r--r--src/tools/miri/tests/panic/unsupported_foreign_function.stderr3
-rw-r--r--src/tools/miri/tests/panic/unsupported_syscall.stderr3
-rw-r--r--src/tools/miri/tests/pass/align_repeat_into_packed_field.rs22
-rw-r--r--src/tools/miri/tests/pass/align_repeat_into_well_aligned_array.rs (renamed from src/tools/miri/tests/pass/issues/issue-miri-1925.rs)2
-rw-r--r--src/tools/miri/tests/pass/concurrency/simple.stderr6
-rw-r--r--src/tools/miri/tests/pass/intrinsics.rs2
-rw-r--r--src/tools/miri/tests/pass/panic/catch_panic.stderr33
-rw-r--r--src/tools/miri/tests/pass/panic/concurrent-panic.stderr6
-rw-r--r--src/tools/miri/tests/pass/panic/nested_panic_caught.stderr6
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr8
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr16
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/formatting.stderr8
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr8
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reserved.stderr24
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs18
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/unique.default.stderr12
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr12
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.default.stderr4
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr4
-rw-r--r--src/tools/opt-dist/Cargo.toml1
-rw-r--r--src/tools/opt-dist/src/bolt.rs98
-rw-r--r--src/tools/opt-dist/src/exec.rs10
-rw-r--r--src/tools/opt-dist/src/main.rs29
-rw-r--r--src/tools/opt-dist/src/tests.rs25
-rw-r--r--src/tools/opt-dist/src/training.rs2
-rw-r--r--src/tools/opt-dist/src/utils/io.rs26
-rw-r--r--src/tools/tidy/src/deps.rs6
-rw-r--r--src/tools/tidy/src/ui_tests.rs4
-rw-r--r--tests/assembly/is_aligned.rs1
-rw-r--r--tests/assembly/slice-is_ascii.rs1
-rw-r--r--tests/assembly/strict_provenance.rs1
-rw-r--r--tests/codegen/abi-main-signature-16bit-c-int.rs20
-rw-r--r--tests/codegen/abi-main-signature-32bit-c-int.rs3
-rw-r--r--tests/codegen/addr-of-mutate.rs1
-rw-r--r--tests/codegen/adjustments.rs6
-rw-r--r--tests/codegen/align-enum.rs2
-rw-r--r--tests/codegen/align-offset.rs1
-rw-r--r--tests/codegen/align-struct.rs4
-rw-r--r--tests/codegen/array-codegen.rs1
-rw-r--r--tests/codegen/array-equality.rs8
-rw-r--r--tests/codegen/atomic-operations.rs60
-rw-r--r--tests/codegen/avr/avr-func-addrspace.rs6
-rw-r--r--tests/codegen/box-maybe-uninit.rs1
-rw-r--r--tests/codegen/comparison-operators-2-tuple.rs1
-rw-r--r--tests/codegen/comparison-operators-newtype.rs1
-rw-r--r--tests/codegen/consts.rs1
-rw-r--r--tests/codegen/drop-in-place-noalias.rs4
-rw-r--r--tests/codegen/fastcall-inreg.rs2
-rw-r--r--tests/codegen/function-arguments-noopt.rs10
-rw-r--r--tests/codegen/function-arguments.rs64
-rw-r--r--tests/codegen/global_asm.rs24
-rw-r--r--tests/codegen/global_asm_include.rs24
-rw-r--r--tests/codegen/global_asm_x2.rs24
-rw-r--r--tests/codegen/intrinsics/mask.rs2
-rw-r--r--tests/codegen/intrinsics/nontemporal.rs2
-rw-r--r--tests/codegen/intrinsics/offset.rs1
-rw-r--r--tests/codegen/intrinsics/transmute-niched.rs1
-rw-r--r--tests/codegen/intrinsics/transmute-x64.rs1
-rw-r--r--tests/codegen/intrinsics/transmute.rs1
-rw-r--r--tests/codegen/issues/issue-105386-ub-in-debuginfo.rs5
-rw-r--r--tests/codegen/issues/issue-37945.rs8
-rw-r--r--tests/codegen/issues/issue-56267-2.rs2
-rw-r--r--tests/codegen/issues/issue-56267.rs2
-rw-r--r--tests/codegen/issues/issue-56927.rs14
-rw-r--r--tests/codegen/issues/issue-58881.rs2
-rw-r--r--tests/codegen/issues/issue-85872-multiple-reverse.rs1
-rw-r--r--tests/codegen/issues/issue-86106.rs1
-rw-r--r--tests/codegen/issues/issue-96274.rs1
-rw-r--r--tests/codegen/issues/issue-96497-slice-size-nowrap.rs1
-rw-r--r--tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs1
-rw-r--r--tests/codegen/lifetime_start_end.rs8
-rw-r--r--tests/codegen/loads.rs34
-rw-r--r--tests/codegen/match-optimized.rs6
-rw-r--r--tests/codegen/mem-replace-big-type.rs4
-rw-r--r--tests/codegen/mem-replace-simple-type.rs1
-rw-r--r--tests/codegen/move-operands.rs4
-rw-r--r--tests/codegen/option-nonzero-eq.rs2
-rw-r--r--tests/codegen/packed.rs40
-rw-r--r--tests/codegen/personality_lifetimes.rs2
-rw-r--r--tests/codegen/refs.rs6
-rw-r--r--tests/codegen/repeat-trusted-len.rs4
-rw-r--r--tests/codegen/repr-transparent-aggregates-1.rs89
-rw-r--r--tests/codegen/repr-transparent-aggregates-2.rs90
-rw-r--r--tests/codegen/repr/transparent-imm-array.rs86
-rw-r--r--tests/codegen/repr/transparent-mips64.rs (renamed from tests/codegen/repr-transparent-aggregates-3.rs)2
-rw-r--r--tests/codegen/repr/transparent-struct-ptr.rs87
-rw-r--r--tests/codegen/repr/transparent-sysv64.rs (renamed from tests/codegen/repr-transparent-sysv64.rs)0
-rw-r--r--tests/codegen/repr/transparent.rs (renamed from tests/codegen/repr-transparent.rs)15
-rw-r--r--tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs10
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-checks.rs2
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs6
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs6
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs6
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs6
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs20
-rw-r--r--tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs20
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs12
-rw-r--r--tests/codegen/simd_arith_offset.rs2
-rw-r--r--tests/codegen/slice-init.rs6
-rw-r--r--tests/codegen/slice-iter-len-eq-zero.rs2
-rw-r--r--tests/codegen/slice-ref-equality.rs12
-rw-r--r--tests/codegen/slice_as_from_ptr_range.rs1
-rw-r--r--tests/codegen/stores.rs8
-rw-r--r--tests/codegen/swap-large-types.rs6
-rw-r--r--tests/codegen/transmute-optimized.rs1
-rw-r--r--tests/codegen/transmute-scalar.rs1
-rw-r--r--tests/codegen/try_question_mark_nop.rs1
-rw-r--r--tests/codegen/unchecked_shifts.rs1
-rw-r--r--tests/codegen/uninit-consts.rs1
-rw-r--r--tests/codegen/union-abi.rs10
-rw-r--r--tests/codegen/vec-as-ptr.rs4
-rw-r--r--tests/codegen/vec-calloc.rs1
-rw-r--r--tests/debuginfo/thread-names.rs13
-rw-r--r--tests/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot2
-rw-r--r--tests/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot4
-rw-r--r--tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff2
-rw-r--r--tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff10
-rw-r--r--tests/run-make/coverage-llvmir/filecheck.testprog.txt4
-rw-r--r--tests/run-make/dump-ice-to-disk/Makefile1
-rw-r--r--tests/run-make/libtest-json/output-default.json2
-rw-r--r--tests/run-make/libtest-json/output-stdout-success.json4
-rw-r--r--tests/run-make/libtest-junit/output-default.xml2
-rw-r--r--tests/run-make/libtest-junit/output-stdout-success.xml2
-rw-r--r--tests/run-make/pgo-indirect-call-promotion/filecheck-patterns.txt4
-rw-r--r--tests/run-make/short-ice/Makefile1
-rw-r--r--tests/rustdoc-gui/rust-logo.goml16
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-output-windows.stdout3
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-output.stdout3
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.rs2
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.stderr3
-rw-r--r--tests/rustdoc/alias-reexport.rs1
-rw-r--r--tests/rustdoc/alias-reexport2.rs1
-rw-r--r--tests/ui/abi/stack-probes-lto.rs12
-rw-r--r--tests/ui/abi/stack-probes.rs11
-rw-r--r--tests/ui/annotate-snippet/auxiliary/other_file.rs6
-rw-r--r--tests/ui/annotate-snippet/multiple-files.rs8
-rw-r--r--tests/ui/annotate-snippet/multiple-files.stderr11
-rw-r--r--tests/ui/asm/x86_64/issue-96797.rs1
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.stderr8
-rw-r--r--tests/ui/async-await/in-trait/async-generics.stderr8
-rw-r--r--tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs3
-rw-r--r--tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs3
-rw-r--r--tests/ui/auto-traits/issue-83857-ub.rs2
-rw-r--r--tests/ui/auto-traits/issue-83857-ub.stderr4
-rw-r--r--tests/ui/binop/borrow-suggestion-109352-2.rs27
-rw-r--r--tests/ui/binop/borrow-suggestion-109352-2.stderr64
-rw-r--r--tests/ui/binop/borrow-suggestion-109352.fixed27
-rw-r--r--tests/ui/binop/borrow-suggestion-109352.rs27
-rw-r--r--tests/ui/binop/borrow-suggestion-109352.stderr45
-rw-r--r--tests/ui/codegen/issue-55976.rs2
-rw-r--r--tests/ui/const-generics/late-bound-vars/in_closure.rs6
-rw-r--r--tests/ui/const-generics/late-bound-vars/in_closure.stderr4
-rw-r--r--tests/ui/const-generics/late-bound-vars/simple.rs4
-rw-r--r--tests/ui/consts/const-eval/const-eval-query-stack.rs4
-rw-r--r--tests/ui/consts/const-eval/nonnull_as_ref.rs8
-rw-r--r--tests/ui/consts/const-eval/nonnull_as_ref_ub.rs6
-rw-r--r--tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr16
-rw-r--r--tests/ui/consts/precise-drop-with-promoted.rs2
-rw-r--r--tests/ui/dyn-star/llvm-old-style-ptrs.rs25
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.rs5
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.stderr4
-rw-r--r--tests/ui/generics/issue-94923.rs1
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.rs2
-rw-r--r--tests/ui/hygiene/panic-location.run.stderr3
-rw-r--r--tests/ui/impl-trait/auto-trait-leak0
-rw-r--r--tests/ui/impl-trait/hidden-type-is-opaque-2.rs6
-rw-r--r--tests/ui/impl-trait/hidden-type-is-opaque-2.stderr24
-rw-r--r--tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs29
-rw-r--r--tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs1
-rw-r--r--tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr17
-rw-r--r--tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs10
-rw-r--r--tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr16
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr24
-rw-r--r--tests/ui/impl-trait/in-trait/wf-bounds.stderr4
-rw-r--r--tests/ui/impl-trait/issues/issue-86800.rs2
-rw-r--r--tests/ui/imports/issue-81413.rs23
-rw-r--r--tests/ui/imports/issue-81413.stderr11
-rw-r--r--tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr3
-rw-r--r--tests/ui/intrinsics/const-eval-select-backtrace.run.stderr3
-rw-r--r--tests/ui/issues/issue-87707.run.stderr6
-rw-r--r--tests/ui/layout/valid_range_oob.stderr1
-rw-r--r--tests/ui/lazy-type-alias/enum-variant.rs (renamed from tests/ui/type-alias/lazy-type-alias-enum-variant.rs)1
-rw-r--r--tests/ui/lazy-type-alias/enum-variant.stderr11
-rw-r--r--tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs14
-rw-r--r--tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.rs8
-rw-r--r--tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr14
-rw-r--r--tests/ui/lexer/lex-emoji-identifiers.rs6
-rw-r--r--tests/ui/lexer/lex-emoji-identifiers.stderr34
-rw-r--r--tests/ui/limits/issue-17913.stderr1
-rw-r--r--tests/ui/macros/assert-eq-macro-msg.rs4
-rw-r--r--tests/ui/macros/assert-macro-explicit.rs2
-rw-r--r--tests/ui/macros/assert-macro-fmt.rs3
-rw-r--r--tests/ui/macros/assert-macro-owned.rs3
-rw-r--r--tests/ui/macros/assert-macro-static.rs3
-rw-r--r--tests/ui/macros/assert-matches-macro-msg.rs4
-rw-r--r--tests/ui/macros/assert-ne-macro-msg.rs4
-rw-r--r--tests/ui/mir/validate/storage-live.stderr1
-rw-r--r--tests/ui/mismatched_types/closure-ref-114180.rs8
-rw-r--r--tests/ui/mismatched_types/closure-ref-114180.stderr22
-rw-r--r--tests/ui/mismatched_types/ref-pat-suggestions.stderr44
-rw-r--r--tests/ui/nll/issue-51345-2.rs3
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-add.rs3
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-mul.rs3
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-neg.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-pow-signed.rs3
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs3
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-sub.rs3
-rw-r--r--tests/ui/panics/default-backtrace-ice.stderr1
-rw-r--r--tests/ui/panics/fmt-only-once.run.stderr3
-rw-r--r--tests/ui/panics/issue-47429-short-backtraces.legacy.run.stderr3
-rw-r--r--tests/ui/panics/issue-47429-short-backtraces.v0.run.stderr3
-rw-r--r--tests/ui/panics/location-detail-panic-no-column.run.stderr3
-rw-r--r--tests/ui/panics/location-detail-panic-no-file.run.stderr3
-rw-r--r--tests/ui/panics/location-detail-panic-no-line.run.stderr3
-rw-r--r--tests/ui/panics/location-detail-panic-no-location-info.run.stderr3
-rw-r--r--tests/ui/panics/location-detail-unwrap-no-file.run.stderr3
-rw-r--r--tests/ui/panics/panic-macro-any-wrapped.rs3
-rw-r--r--tests/ui/panics/panic-macro-any.rs3
-rw-r--r--tests/ui/panics/panic-macro-explicit.rs3
-rw-r--r--tests/ui/panics/panic-macro-fmt.rs3
-rw-r--r--tests/ui/panics/panic-macro-owned.rs3
-rw-r--r--tests/ui/panics/panic-macro-static.rs3
-rw-r--r--tests/ui/panics/panic-set-unset-handler.rs3
-rw-r--r--tests/ui/panics/panic-take-handler-nop.rs3
-rw-r--r--tests/ui/panics/panic-task-name-none.rs3
-rw-r--r--tests/ui/panics/panic-task-name-owned.rs3
-rw-r--r--tests/ui/panics/runtime-switch.legacy.run.stderr3
-rw-r--r--tests/ui/panics/runtime-switch.v0.run.stderr3
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr5
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames.run.stderr4
-rw-r--r--tests/ui/parser/ternary_operator.rs69
-rw-r--r--tests/ui/parser/ternary_operator.stderr115
-rw-r--r--tests/ui/privacy/unnameable_types.rs4
-rw-r--r--tests/ui/privacy/unnameable_types.stderr14
-rw-r--r--tests/ui/proc-macro/load-panic-backtrace.stderr3
-rw-r--r--tests/ui/process/multi-panic.rs4
-rw-r--r--tests/ui/process/println-with-broken-pipe.run.stderr3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs5
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr10
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-2.rs28
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-2.stderr80
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-pass.rs35
-rw-r--r--tests/ui/simd/intrinsic/generic-bswap-byte.rs22
-rw-r--r--tests/ui/target-feature/gate.rs15
-rw-r--r--tests/ui/target-feature/gate.stderr2
-rw-r--r--tests/ui/target-feature/invalid-attribute.rs14
-rw-r--r--tests/ui/target-feature/invalid-attribute.stderr44
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr10
-rw-r--r--tests/ui/test-attrs/test-panic-abort.run.stdout5
-rw-r--r--tests/ui/test-attrs/test-thread-capture.run.stdout3
-rw-r--r--tests/ui/test-attrs/test-thread-nocapture.run.stderr3
-rw-r--r--tests/ui/threads-sendsync/issue-24313.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr13
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr13
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs14
-rw-r--r--tests/ui/treat-err-as-bug/delay_span_bug.rs2
-rw-r--r--tests/ui/treat-err-as-bug/err.rs2
878 files changed, 13952 insertions, 7236 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0842b69c219..4121e392ae8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -55,7 +55,7 @@ jobs:
           - name: mingw-check-tidy
             os: ubuntu-20.04-16core-64gb
             env: {}
-          - name: x86_64-gnu-llvm-14
+          - name: x86_64-gnu-llvm-15
             os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-tools
@@ -293,10 +293,6 @@ jobs:
             env:
               RUST_BACKTRACE: 1
             os: ubuntu-20.04-8core-32gb
-          - name: x86_64-gnu-llvm-14
-            env:
-              RUST_BACKTRACE: 1
-            os: ubuntu-20.04-8core-32gb
           - name: x86_64-gnu-nopt
             os: ubuntu-20.04-4core-16gb
             env: {}
@@ -422,7 +418,6 @@ jobs:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
-              WINDOWS_SDK_20348_HACK: 1
             os: windows-2019-8core-32gb
           - name: dist-i686-mingw
             env:
diff --git a/.gitmodules b/.gitmodules
index 6b7160bfe15..b48fddf963f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,34 +1,45 @@
 [submodule "src/doc/nomicon"]
 	path = src/doc/nomicon
 	url = https://github.com/rust-lang/nomicon.git
+	shallow = true
 [submodule "src/tools/cargo"]
 	path = src/tools/cargo
 	url = https://github.com/rust-lang/cargo.git
+	shallow = true
 [submodule "src/doc/reference"]
 	path = src/doc/reference
 	url = https://github.com/rust-lang/reference.git
+	shallow = true
 [submodule "src/doc/book"]
 	path = src/doc/book
 	url = https://github.com/rust-lang/book.git
+	shallow = true
 [submodule "src/doc/rust-by-example"]
 	path = src/doc/rust-by-example
 	url = https://github.com/rust-lang/rust-by-example.git
+	shallow = true
 [submodule "library/stdarch"]
 	path = library/stdarch
 	url = https://github.com/rust-lang/stdarch.git
+	shallow = true
 [submodule "src/doc/rustc-dev-guide"]
 	path = src/doc/rustc-dev-guide
 	url = https://github.com/rust-lang/rustc-dev-guide.git
+	shallow = true
 [submodule "src/doc/edition-guide"]
 	path = src/doc/edition-guide
 	url = https://github.com/rust-lang/edition-guide.git
+	shallow = true
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
 	branch = rustc/16.0-2023-06-05
+	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
+	shallow = true
 [submodule "library/backtrace"]
 	path = library/backtrace
 	url = https://github.com/rust-lang/backtrace-rs.git
+	shallow = true
diff --git a/Cargo.lock b/Cargo.lock
index 45959c039e7..9f6df6e14c6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2495,6 +2495,7 @@ dependencies = [
  "serde_json",
  "sysinfo",
  "tar",
+ "tempfile",
  "xz",
  "zip",
 ]
@@ -3785,7 +3786,7 @@ name = "rustc_lexer"
 version = "0.1.0"
 dependencies = [
  "expect-test",
- "unic-emoji-char",
+ "unicode-properties",
  "unicode-xid",
 ]
 
@@ -5446,38 +5447,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "unic-char-property"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
-dependencies = [
- "unic-char-range",
-]
-
-[[package]]
-name = "unic-char-range"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
-
-[[package]]
-name = "unic-common"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
-
-[[package]]
-name = "unic-emoji-char"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
-dependencies = [
- "unic-char-property",
- "unic-char-range",
- "unic-ucd-version",
-]
-
-[[package]]
 name = "unic-langid"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5521,15 +5490,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "unic-ucd-version"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
-dependencies = [
- "unic-common",
-]
-
-[[package]]
 name = "unicase"
 version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5567,6 +5527,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "unicode-properties"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
+
+[[package]]
 name = "unicode-script"
 version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs
index 39cf3e094c8..8b7d28d2b8a 100644
--- a/compiler/rustc/build.rs
+++ b/compiler/rustc/build.rs
@@ -18,7 +18,7 @@ fn set_windows_exe_options() {
     let mut manifest = env::current_dir().unwrap();
     manifest.push(WINDOWS_MANIFEST_FILE);
 
-    println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
+    println!("cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}");
     // Embed the Windows application manifest file.
     println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");
     println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap());
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 489a8403c3b..a8a1a90572d 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -260,8 +260,7 @@ pub trait LayoutCalculator {
                 }
                 _ => assert!(
                     start == Bound::Unbounded && end == Bound::Unbounded,
-                    "nonscalar layout for layout_scalar_valid_range type: {:#?}",
-                    st,
+                    "nonscalar layout for layout_scalar_valid_range type: {st:#?}",
                 ),
             }
 
@@ -463,7 +462,7 @@ pub trait LayoutCalculator {
             min = 0;
             max = 0;
         }
-        assert!(min <= max, "discriminant range is {}...{}", min, max);
+        assert!(min <= max, "discriminant range is {min}...{max}");
         let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
 
         let mut align = dl.aggregate_align;
@@ -537,8 +536,7 @@ pub trait LayoutCalculator {
             // space necessary to represent would have to be discarded (or layout is wrong
             // on thinking it needs 16 bits)
             panic!(
-                "layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
-                min_ity, typeck_ity
+                "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})"
             );
             // However, it is fine to make discr type however large (as an optimisation)
             // after this point – we’ll just truncate the value we load in codegen.
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 835143407d2..1442747fe1e 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -332,7 +332,7 @@ impl TargetDataLayout {
             16 => 1 << 15,
             32 => 1 << 31,
             64 => 1 << 47,
-            bits => panic!("obj_size_bound: unknown pointer bit size {}", bits),
+            bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
         }
     }
 
@@ -342,7 +342,7 @@ impl TargetDataLayout {
             16 => I16,
             32 => I32,
             64 => I64,
-            bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits),
+            bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
         }
     }
 
@@ -399,7 +399,7 @@ impl FromStr for Endian {
         match s {
             "little" => Ok(Self::Little),
             "big" => Ok(Self::Big),
-            _ => Err(format!(r#"unknown endian: "{}""#, s)),
+            _ => Err(format!(r#"unknown endian: "{s}""#)),
         }
     }
 }
@@ -456,7 +456,7 @@ impl Size {
     pub fn bits(self) -> u64 {
         #[cold]
         fn overflow(bytes: u64) -> ! {
-            panic!("Size::bits: {} bytes in bits doesn't fit in u64", bytes)
+            panic!("Size::bits: {bytes} bytes in bits doesn't fit in u64")
         }
 
         self.bytes().checked_mul(8).unwrap_or_else(|| overflow(self.bytes()))
@@ -1179,17 +1179,12 @@ impl FieldsShape {
                 unreachable!("FieldsShape::offset: `Primitive`s have no fields")
             }
             FieldsShape::Union(count) => {
-                assert!(
-                    i < count.get(),
-                    "tried to access field {} of union with {} fields",
-                    i,
-                    count
-                );
+                assert!(i < count.get(), "tried to access field {i} of union with {count} fields");
                 Size::ZERO
             }
             FieldsShape::Array { stride, count } => {
                 let i = u64::try_from(i).unwrap();
-                assert!(i < count, "tried to access field {} of array with {} fields", i, count);
+                assert!(i < count, "tried to access field {i} of array with {count} fields");
                 stride * i
             }
             FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)],
@@ -1294,7 +1289,7 @@ impl Abi {
                 Primitive::Int(_, signed) => signed,
                 _ => false,
             },
-            _ => panic!("`is_signed` on non-scalar ABI {:?}", self),
+            _ => panic!("`is_signed` on non-scalar ABI {self:?}"),
         }
     }
 
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 348c37c480f..e9591c7c8db 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -13,7 +13,7 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::ast::StmtKind;
+use crate::ast::{AttrStyle, StmtKind};
 use crate::ast_traits::{HasAttrs, HasSpan, HasTokens};
 use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
 use crate::AttrVec;
@@ -22,11 +22,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
-use std::{fmt, iter, mem};
+use std::{cmp, fmt, iter, mem};
 
 /// When the main Rust parser encounters a syntax-extension invocation, it
 /// parses the arguments to the invocation as a token tree. This is a very
@@ -566,6 +566,92 @@ impl TokenStream {
     pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> {
         self.0.chunks(chunk_size)
     }
+
+    /// Desugar doc comments like `/// foo` in the stream into `#[doc =
+    /// r"foo"]`. Modifies the `TokenStream` via `Lrc::make_mut`, but as little
+    /// as possible.
+    pub fn desugar_doc_comments(&mut self) {
+        if let Some(desugared_stream) = desugar_inner(self.clone()) {
+            *self = desugared_stream;
+        }
+
+        // The return value is `None` if nothing in `stream` changed.
+        fn desugar_inner(mut stream: TokenStream) -> Option<TokenStream> {
+            let mut i = 0;
+            let mut modified = false;
+            while let Some(tt) = stream.0.get(i) {
+                match tt {
+                    &TokenTree::Token(
+                        Token { kind: token::DocComment(_, attr_style, data), span },
+                        _spacing,
+                    ) => {
+                        let desugared = desugared_tts(attr_style, data, span);
+                        let desugared_len = desugared.len();
+                        Lrc::make_mut(&mut stream.0).splice(i..i + 1, desugared);
+                        modified = true;
+                        i += desugared_len;
+                    }
+
+                    &TokenTree::Token(..) => i += 1,
+
+                    &TokenTree::Delimited(sp, delim, ref delim_stream) => {
+                        if let Some(desugared_delim_stream) = desugar_inner(delim_stream.clone()) {
+                            let new_tt = TokenTree::Delimited(sp, delim, desugared_delim_stream);
+                            Lrc::make_mut(&mut stream.0)[i] = new_tt;
+                            modified = true;
+                        }
+                        i += 1;
+                    }
+                }
+            }
+            if modified { Some(stream) } else { None }
+        }
+
+        fn desugared_tts(attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
+            // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
+            // required to wrap the text. E.g.
+            // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
+            // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
+            // - `abc "##d##"` is wrapped as `r###"abc ##"d"##"###` (num_of_hashes = 3)
+            let mut num_of_hashes = 0;
+            let mut count = 0;
+            for ch in data.as_str().chars() {
+                count = match ch {
+                    '"' => 1,
+                    '#' if count > 0 => count + 1,
+                    _ => 0,
+                };
+                num_of_hashes = cmp::max(num_of_hashes, count);
+            }
+
+            // `/// foo` becomes `doc = r"foo"`.
+            let delim_span = DelimSpan::from_single(span);
+            let body = TokenTree::Delimited(
+                delim_span,
+                Delimiter::Bracket,
+                [
+                    TokenTree::token_alone(token::Ident(sym::doc, false), span),
+                    TokenTree::token_alone(token::Eq, span),
+                    TokenTree::token_alone(
+                        TokenKind::lit(token::StrRaw(num_of_hashes), data, None),
+                        span,
+                    ),
+                ]
+                .into_iter()
+                .collect::<TokenStream>(),
+            );
+
+            if attr_style == AttrStyle::Inner {
+                vec![
+                    TokenTree::token_alone(token::Pound, span),
+                    TokenTree::token_alone(token::Not, span),
+                    body,
+                ]
+            } else {
+                vec![TokenTree::token_alone(token::Pound, span), body]
+            }
+        }
+    }
 }
 
 /// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
@@ -628,15 +714,6 @@ impl TokenTreeCursor {
     pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
         self.stream.0.get(self.index + n)
     }
-
-    // Replace the previously obtained token tree with `tts`, and rewind to
-    // just before them.
-    pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) {
-        assert!(self.index > 0);
-        self.index -= 1;
-        let stream = Lrc::make_mut(&mut self.stream.0);
-        stream.splice(self.index..self.index + 1, tts);
-    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 418e1df5857..af594a00705 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -659,7 +659,7 @@ fn validate_generic_param_order(
             GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
             GenericParamKind::Const { ty, .. } => {
                 let ty = pprust::ty_to_string(ty);
-                (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
+                (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))
             }
         };
         param_idents.push((kind, ord_kind, bounds, idx, ident));
@@ -1463,15 +1463,12 @@ fn deny_equality_constraints(
                                             let Some(arg) = args.args.last() else {
                                                 continue;
                                             };
-                                            (
-                                                format!(", {} = {}", assoc, ty),
-                                                arg.span().shrink_to_hi(),
-                                            )
+                                            (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
                                         }
                                         _ => continue,
                                     },
                                     None => (
-                                        format!("<{} = {}>", assoc, ty),
+                                        format!("<{assoc} = {ty}>"),
                                         trait_segment.span().shrink_to_hi(),
                                     ),
                                 };
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 0152d89eb83..df5e383ad40 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -353,7 +353,6 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
         let tcx = self.tcx;
         let body = self.body;
         let borrow_set = self.borrow_set;
-        let indices = self.borrow_set.indices();
         each_borrow_involving_path(
             self,
             tcx,
@@ -361,7 +360,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
             location,
             (sd, place),
             borrow_set,
-            indices,
+            |_| true,
             |this, borrow_index, borrow| {
                 match (rw, borrow.kind) {
                     // Obviously an activation is compatible with its own
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index ba1d31ee002..317af8ae1f6 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -23,7 +23,7 @@ use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, Subdiagnost
 use rustc_fluent_macro::fluent_messages;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_index::bit_set::ChunkedBitSet;
+use rustc_index::bit_set::{BitSet, ChunkedBitSet};
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::{
     InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
@@ -42,7 +42,6 @@ use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
 use rustc_target::abi::FieldIdx;
 
-use either::Either;
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
@@ -1035,12 +1034,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let borrow_set = self.borrow_set.clone();
 
         // Use polonius output if it has been enabled.
-        let polonius_output = self.polonius_output.clone();
-        let borrows_in_scope = if let Some(polonius) = &polonius_output {
+        let mut polonius_output;
+        let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
             let location = self.location_table.start_index(location);
-            Either::Left(polonius.errors_at(location).iter().copied())
+            polonius_output = BitSet::new_empty(borrow_set.len());
+            for &idx in polonius.errors_at(location) {
+                polonius_output.insert(idx);
+            }
+            &polonius_output
         } else {
-            Either::Right(flow_state.borrows.iter())
+            &flow_state.borrows
         };
 
         each_borrow_involving_path(
@@ -1050,7 +1053,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             location,
             (sd, place_span.0),
             &borrow_set,
-            borrows_in_scope,
+            |borrow_index| borrows_in_scope.contains(borrow_index),
             |this, borrow_index, borrow| match (rw, borrow.kind) {
                 // Obviously an activation is compatible with its own
                 // reservation (or even prior activating uses of same
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index ea9f8683ca7..ed93a560981 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -33,20 +33,24 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
     _location: Location,
     access_place: (AccessDepth, Place<'tcx>),
     borrow_set: &BorrowSet<'tcx>,
-    candidates: I,
+    is_candidate: I,
     mut op: F,
 ) where
     F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
-    I: Iterator<Item = BorrowIndex>,
+    I: Fn(BorrowIndex) -> bool,
 {
     let (access, place) = access_place;
 
-    // FIXME: analogous code in check_loans first maps `place` to
-    // its base_path.
+    // The number of candidates can be large, but borrows for different locals cannot conflict with
+    // each other, so we restrict the working set a priori.
+    let Some(borrows_for_place_base) = borrow_set.local_map.get(&place.local) else { return };
 
     // check for loan restricting path P being used. Accounts for
     // borrows of P, P.a.b, etc.
-    for i in candidates {
+    for &i in borrows_for_place_base {
+        if !is_candidate(i) {
+            continue;
+        }
         let borrowed = &borrow_set[i];
 
         if places_conflict::borrow_conflicts_with_place(
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 1217dcb9c40..c02f6f3b687 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -1,3 +1,55 @@
+//! The borrowck rules for proving disjointness are applied from the "root" of the
+//! borrow forwards, iterating over "similar" projections in lockstep until
+//! we can prove overlap one way or another. Essentially, we treat `Overlap` as
+//! a monoid and report a conflict if the product ends up not being `Disjoint`.
+//!
+//! At each step, if we didn't run out of borrow or place, we know that our elements
+//! have the same type, and that they only overlap if they are the identical.
+//!
+//! For example, if we are comparing these:
+//! ```text
+//! BORROW:  (*x1[2].y).z.a
+//! ACCESS:  (*x1[i].y).w.b
+//! ```
+//!
+//! Then our steps are:
+//! ```text
+//!       x1         |   x1          -- places are the same
+//!       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)
+//!       x1[2].y    |   x1[i].y     -- equal or disjoint
+//!      *x1[2].y    |  *x1[i].y     -- equal or disjoint
+//!     (*x1[2].y).z | (*x1[i].y).w  -- we are disjoint and don't need to check more!
+//! ```
+//!
+//! Because `zip` does potentially bad things to the iterator inside, this loop
+//! also handles the case where the access might be a *prefix* of the borrow, e.g.
+//!
+//! ```text
+//! BORROW:  (*x1[2].y).z.a
+//! ACCESS:  x1[i].y
+//! ```
+//!
+//! Then our steps are:
+//! ```text
+//!       x1         |   x1          -- places are the same
+//!       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)
+//!       x1[2].y    |   x1[i].y     -- equal or disjoint
+//! ```
+//!
+//! -- here we run out of access - the borrow can access a part of it. If this
+//! is a full deep access, then we *know* the borrow conflicts with it. However,
+//! if the access is shallow, then we can proceed:
+//!
+//! ```text
+//!       x1[2].y    | (*x1[i].y)    -- a deref! the access can't get past this, so we
+//!                                     are disjoint
+//! ```
+//!
+//! Our invariant is, that at each step of the iteration:
+//!  - If we didn't run out of access to match, our borrow and access are comparable
+//!    and either equal or disjoint.
+//!  - If we did run out of access, the borrow can access a part of it.
+
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 use crate::ArtificialField;
@@ -5,7 +57,7 @@ use crate::Overlap;
 use crate::{AccessDepth, Deep, Shallow};
 use rustc_hir as hir;
 use rustc_middle::mir::{
-    Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
+    Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
 };
 use rustc_middle::ty::{self, TyCtxt};
 use std::cmp::max;
@@ -48,7 +100,7 @@ pub fn places_conflict<'tcx>(
 /// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
 /// array indices, for example) should be interpreted - this depends on what the caller wants in
 /// order to make the conservative choice and preserve soundness.
-#[instrument(level = "debug", skip(tcx, body))]
+#[inline]
 pub(super) fn borrow_conflicts_with_place<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -58,15 +110,24 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
+    let borrow_local = borrow_place.local;
+    let access_local = access_place.local;
+
+    if borrow_local != access_local {
+        // We have proven the borrow disjoint - further projections will remain disjoint.
+        return false;
+    }
+
     // This Local/Local case is handled by the more general code below, but
     // it's so common that it's a speed win to check for it first.
-    if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
-        return l1 == l2;
+    if borrow_place.projection.is_empty() && access_place.projection.is_empty() {
+        return true;
     }
 
     place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)
 }
 
+#[instrument(level = "debug", skip(tcx, body))]
 fn place_components_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -76,65 +137,10 @@ fn place_components_conflict<'tcx>(
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
-    // The borrowck rules for proving disjointness are applied from the "root" of the
-    // borrow forwards, iterating over "similar" projections in lockstep until
-    // we can prove overlap one way or another. Essentially, we treat `Overlap` as
-    // a monoid and report a conflict if the product ends up not being `Disjoint`.
-    //
-    // At each step, if we didn't run out of borrow or place, we know that our elements
-    // have the same type, and that they only overlap if they are the identical.
-    //
-    // For example, if we are comparing these:
-    // BORROW:  (*x1[2].y).z.a
-    // ACCESS:  (*x1[i].y).w.b
-    //
-    // Then our steps are:
-    //       x1         |   x1          -- places are the same
-    //       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)
-    //       x1[2].y    |   x1[i].y     -- equal or disjoint
-    //      *x1[2].y    |  *x1[i].y     -- equal or disjoint
-    //     (*x1[2].y).z | (*x1[i].y).w  -- we are disjoint and don't need to check more!
-    //
-    // Because `zip` does potentially bad things to the iterator inside, this loop
-    // also handles the case where the access might be a *prefix* of the borrow, e.g.
-    //
-    // BORROW:  (*x1[2].y).z.a
-    // ACCESS:  x1[i].y
-    //
-    // Then our steps are:
-    //       x1         |   x1          -- places are the same
-    //       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)
-    //       x1[2].y    |   x1[i].y     -- equal or disjoint
-    //
-    // -- here we run out of access - the borrow can access a part of it. If this
-    // is a full deep access, then we *know* the borrow conflicts with it. However,
-    // if the access is shallow, then we can proceed:
-    //
-    //       x1[2].y    | (*x1[i].y)    -- a deref! the access can't get past this, so we
-    //                                     are disjoint
-    //
-    // Our invariant is, that at each step of the iteration:
-    //  - If we didn't run out of access to match, our borrow and access are comparable
-    //    and either equal or disjoint.
-    //  - If we did run out of access, the borrow can access a part of it.
-
     let borrow_local = borrow_place.local;
     let access_local = access_place.local;
-
-    match place_base_conflict(borrow_local, access_local) {
-        Overlap::Arbitrary => {
-            bug!("Two base can't return Arbitrary");
-        }
-        Overlap::EqualOrDisjoint => {
-            // This is the recursive case - proceed to the next element.
-        }
-        Overlap::Disjoint => {
-            // We have proven the borrow disjoint - further
-            // projections will remain disjoint.
-            debug!("borrow_conflicts_with_place: disjoint");
-            return false;
-        }
-    }
+    // borrow_conflicts_with_place should have checked that.
+    assert_eq!(borrow_local, access_local);
 
     // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
     for ((borrow_place, borrow_c), &access_c) in
@@ -280,21 +286,6 @@ fn place_components_conflict<'tcx>(
 // Given that the bases of `elem1` and `elem2` are always either equal
 // or disjoint (and have the same type!), return the overlap situation
 // between `elem1` and `elem2`.
-fn place_base_conflict(l1: Local, l2: Local) -> Overlap {
-    if l1 == l2 {
-        // the same local - base case, equal
-        debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
-        Overlap::EqualOrDisjoint
-    } else {
-        // different locals - base case, disjoint
-        debug!("place_element_conflict: DISJOINT-LOCAL");
-        Overlap::Disjoint
-    }
-}
-
-// Given that the bases of `elem1` and `elem2` are always either equal
-// or disjoint (and have the same type!), return the overlap situation
-// between `elem1` and `elem2`.
 fn place_projection_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 21f45935218..9e66eaf73b3 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -575,7 +575,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 || named_pos.contains_key(&idx)
                                 || args.reg_args.contains(idx)
                             {
-                                let msg = format!("invalid reference to argument at index {}", idx);
+                                let msg = format!("invalid reference to argument at index {idx}");
                                 let mut err = ecx.struct_span_err(span, msg);
                                 err.span_label(span, "from here");
 
@@ -588,9 +588,9 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                     ""
                                 };
                                 let msg = match positional_args {
-                                    0 => format!("no {}arguments were given", positional),
-                                    1 => format!("there is 1 {}argument", positional),
-                                    x => format!("there are {} {}arguments", x, positional),
+                                    0 => format!("no {positional}arguments were given"),
+                                    1 => format!("there is 1 {positional}argument"),
+                                    x => format!("there are {x} {positional}arguments"),
                                 };
                                 err.note(msg);
 
@@ -624,7 +624,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                             match args.named_args.get(&Symbol::intern(name)) {
                                 Some(&idx) => Some(idx),
                                 None => {
-                                    let msg = format!("there is no argument named `{}`", name);
+                                    let msg = format!("there is no argument named `{name}`");
                                     let span = arg.position_span;
                                     ecx.struct_span_err(
                                         template_span
@@ -697,8 +697,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             err.span_label(sp, msg);
             err.help(format!(
                 "if this argument is intentionally unused, \
-                 consider using it in an asm comment: `\"/*{} */\"`",
-                help_str
+                 consider using it in an asm comment: `\"/*{help_str} */\"`"
             ));
             err.emit();
         }
@@ -712,8 +711,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             }
             err.help(format!(
                 "if these arguments are intentionally unused, \
-                 consider using them in an asm comment: `\"/*{} */\"`",
-                help_str
+                 consider using them in an asm comment: `\"/*{help_str} */\"`"
             ));
             err.emit();
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 9ba98d0a5d1..b468abe3249 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -144,7 +144,7 @@ fn cs_clone_simple(
             }
             _ => cx.span_bug(
                 trait_span,
-                format!("unexpected substructure in simple `derive({})`", name),
+                format!("unexpected substructure in simple `derive({name})`"),
             ),
         }
     }
@@ -178,10 +178,10 @@ fn cs_clone(
             vdata = &variant.data;
         }
         EnumTag(..) | AllFieldlessEnum(..) => {
-            cx.span_bug(trait_span, format!("enum tags in `derive({})`", name,))
+            cx.span_bug(trait_span, format!("enum tags in `derive({name})`",))
         }
         StaticEnum(..) | StaticStruct(..) => {
-            cx.span_bug(trait_span, format!("associated function in `derive({})`", name))
+            cx.span_bug(trait_span, format!("associated function in `derive({name})`"))
         }
     }
 
@@ -193,7 +193,7 @@ fn cs_clone(
                     let Some(ident) = field.name else {
                         cx.span_bug(
                             trait_span,
-                            format!("unnamed field in normal struct in `derive({})`", name,),
+                            format!("unnamed field in normal struct in `derive({name})`",),
                         );
                     };
                     let call = subcall(cx, field);
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 3921533c84a..bcf11cb4ce9 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -204,7 +204,7 @@ where
                 let fields = fields
                     .iter()
                     .enumerate()
-                    .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{}", i)), i))
+                    .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i))
                     .collect();
 
                 cx.expr_call(trait_span, path_expr, fields)
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index a3b11309d0c..2dc20c32497 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -173,7 +173,7 @@ fn encodable_substructure(
             for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
                     Some(id) => id.name,
-                    None => Symbol::intern(&format!("_field{}", i)),
+                    None => Symbol::intern(&format!("_field{i}")),
                 };
                 let self_ref = cx.expr_addr_of(span, self_expr.clone());
                 let enc =
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 9865b6a72ee..6597ee3cf1b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1166,7 +1166,7 @@ impl<'a> MethodDef<'a> {
                     .iter()
                     .enumerate()
                     .skip(1)
-                    .map(|(arg_count, _selflike_arg)| format!("__arg{}", arg_count)),
+                    .map(|(arg_count, _selflike_arg)| format!("__arg{arg_count}")),
             )
             .collect::<Vec<String>>();
 
@@ -1181,7 +1181,7 @@ impl<'a> MethodDef<'a> {
         let get_tag_pieces = |cx: &ExtCtxt<'_>| {
             let tag_idents: Vec<_> = prefixes
                 .iter()
-                .map(|name| Ident::from_str_and_span(&format!("{}_tag", name), span))
+                .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
                 .collect();
 
             let mut tag_exprs: Vec<_> = tag_idents
@@ -1521,7 +1521,7 @@ impl<'a> TraitDef<'a> {
     }
 
     fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
-        Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span)
+        Ident::from_str_and_span(&format!("{prefix}_{i}"), self.span)
     }
 
     fn create_struct_pattern_fields(
@@ -1602,8 +1602,7 @@ impl<'a> TraitDef<'a> {
                                 sp,
                                 ast::CRATE_NODE_ID,
                                 format!(
-                                    "{} slice in a packed struct that derives a built-in trait",
-                                    ty
+                                    "{ty} slice in a packed struct that derives a built-in trait"
                                 ),
                                 rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
                             );
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 4c878785b7b..590db12a4cd 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -179,7 +179,7 @@ fn make_format_args(
                     err.span_suggestion(
                         unexpanded_fmt_span.shrink_to_lo(),
                         "you might be missing a string literal to format with",
-                        format!("\"{}\", ", sugg_fmt),
+                        format!("\"{sugg_fmt}\", "),
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -668,7 +668,7 @@ fn report_invalid_references(
     let num_args_desc = match args.explicit_args().len() {
         0 => "no arguments were given".to_string(),
         1 => "there is 1 argument".to_string(),
-        n => format!("there are {} arguments", n),
+        n => format!("there are {n} arguments"),
     };
 
     let mut e;
@@ -780,7 +780,7 @@ fn report_invalid_references(
                         if num_placeholders == 1 {
                             "is 1 argument".to_string()
                         } else {
-                            format!("are {} arguments", num_placeholders)
+                            format!("are {num_placeholders} arguments")
                         },
                     ),
                 );
@@ -811,7 +811,7 @@ fn report_invalid_references(
         };
         e = ecx.struct_span_err(
             span,
-            format!("invalid reference to positional {} ({})", arg_list, num_args_desc),
+            format!("invalid reference to positional {arg_list} ({num_args_desc})"),
         );
         e.note("positional arguments are zero-based");
     }
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index bd5356575ca..2fc8a076366 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -86,10 +86,7 @@ pub(crate) mod printf {
                         '-' => c_left = true,
                         '+' => c_plus = true,
                         _ => {
-                            return Err(Some(format!(
-                                "the flag `{}` is unknown or unsupported",
-                                c
-                            )));
+                            return Err(Some(format!("the flag `{c}` is unknown or unsupported")));
                         }
                     }
                 }
@@ -268,21 +265,21 @@ pub(crate) mod printf {
     impl Num {
         fn from_str(s: &str, arg: Option<&str>) -> Self {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{:?}`", arg)))
+                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
             } else if s == "*" {
                 Num::Next
             } else {
-                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{:?}`", s)))
+                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
             }
         }
 
         fn translate(&self, s: &mut String) -> std::fmt::Result {
             use std::fmt::Write;
             match *self {
-                Num::Num(n) => write!(s, "{}", n),
+                Num::Num(n) => write!(s, "{n}"),
                 Num::Arg(n) => {
                     let n = n.checked_sub(1).ok_or(std::fmt::Error)?;
-                    write!(s, "{}$", n)
+                    write!(s, "{n}$")
                 }
                 Num::Next => write!(s, "*"),
             }
@@ -626,8 +623,8 @@ pub mod shell {
     impl Substitution<'_> {
         pub fn as_str(&self) -> String {
             match self {
-                Substitution::Ordinal(n, _) => format!("${}", n),
-                Substitution::Name(n, _) => format!("${}", n),
+                Substitution::Ordinal(n, _) => format!("${n}"),
+                Substitution::Name(n, _) => format!("${n}"),
                 Substitution::Escape(_) => "$$".into(),
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 5772471931f..053f5730f6e 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -72,7 +72,7 @@ impl AllocFnFactory<'_, '_> {
         let mut abi_args = ThinVec::new();
         let mut i = 0;
         let mut mk = || {
-            let name = Ident::from_str_and_span(&format!("arg{}", i), self.span);
+            let name = Ident::from_str_and_span(&format!("arg{i}"), self.span);
             i += 1;
             name
         };
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index a7908373b6d..7c0b36ced96 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -179,8 +179,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                         == prev_item.path.segments[0].ident.name
                     {
                         format!(
-                            "only one `#[{}]` attribute is allowed on any given function",
-                            path_str,
+                            "only one `#[{path_str}]` attribute is allowed on any given function",
                         )
                     } else {
                         format!(
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index e613b904d2e..433da74231f 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -149,7 +149,7 @@ pub fn expand_include<'cx>(
                     Ok(None) => {
                         if self.p.token != token::Eof {
                             let token = pprust::token_to_string(&self.p.token);
-                            let msg = format!("expected item, found `{}`", token);
+                            let msg = format!("expected item, found `{token}`");
                             self.p.struct_span_err(self.p.token.span, msg).emit();
                         }
 
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 43d0aafbd50..0b1f2fe6a87 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -27,7 +27,6 @@ use rustc_codegen_ssa::traits::{
     BaseTypeMethods,
     BuilderMethods,
     ConstMethods,
-    DerivedTypeMethods,
     LayoutTypeMethods,
     HasCodegen,
     OverflowOp,
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index b62f4676f70..5f54cb16d8e 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -16,6 +16,10 @@ use crate::context::CodegenCx;
 use crate::type_of::LayoutGccExt;
 
 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, val, ty)
+    }
+
     pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
         bytes_in_context(self, bytes)
     }
@@ -242,10 +246,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         const_alloc_to_gcc(self, alloc)
     }
 
-    fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
-        self.context.new_cast(None, val, ty)
-    }
-
     fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
         if value.get_type() == self.bool_type.make_pointer() {
             if let Some(pointee) = typ.get_pointee() {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index b75546447e3..68edde13829 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -12,7 +12,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
 #[cfg(feature="master")]
-use rustc_codegen_ssa::traits::{DerivedTypeMethods, MiscMethods};
+use rustc_codegen_ssa::traits::MiscMethods;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Instance, Ty};
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 04ac0254a81..697ae015fed 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -71,7 +71,7 @@ use gccjit::{Context, OptimizationLevel, CType};
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_codegen_ssa::base::codegen_crate;
-use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
@@ -217,14 +217,14 @@ impl WriteBackendMethods for GccCodegenBackend {
     type ThinData = ();
     type ThinBuffer = ThinBuffer;
 
-    fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
+    fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLtoInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
         // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
         // NOTE: implemented elsewhere.
         // TODO(antoyo): what is implemented elsewhere ^ ?
         let module =
             match modules.remove(0) {
-                FatLTOInput::InMemory(module) => module,
-                FatLTOInput::Serialized { .. } => {
+                FatLtoInput::InMemory(module) => module,
+                FatLtoInput::Serialized { .. } => {
                     unimplemented!();
                 }
             };
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index 521b64ad34d..31899740514 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -54,6 +54,23 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         self.u128_type
     }
 
+    pub fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
+        ty.make_pointer()
+    }
+
+    pub fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
+        // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE?
+        ty.make_pointer()
+    }
+
+    pub fn type_i8p(&self) -> Type<'gcc> {
+        self.type_ptr_to(self.type_i8())
+    }
+
+    pub fn type_i8p_ext(&self, address_space: AddressSpace) -> Type<'gcc> {
+        self.type_ptr_to_ext(self.type_i8(), address_space)
+    }
+
     pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> {
         // FIXME(eddyb) We could find a better approximation if ity.align < align.
         let ity = Integer::approximate_align(self, align);
@@ -149,13 +166,12 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
     }
 
-    fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
-        ty.make_pointer()
+    fn type_ptr(&self) -> Type<'gcc> {
+        self.type_ptr_to(self.type_void())
     }
 
-    fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
-        // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE?
-        ty.make_pointer()
+    fn type_ptr_ext(&self, address_space: AddressSpace) -> Type<'gcc> {
+        self.type_ptr_to_ext(self.type_void(), address_space)
     }
 
     fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index d221bad28ef..e02b457fd0b 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -216,9 +216,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
             let can_store_through_cast_ptr = false;
             if can_store_through_cast_ptr {
-                let cast_ptr_llty = bx.type_ptr_to(cast.llvm_type(bx));
-                let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
-                bx.store(val, cast_dst, self.layout.align.abi);
+                bx.store(val, dst.llval, self.layout.align.abi);
             } else {
                 // The actual return type is a struct, but the ABI
                 // adaptation code has cast it into some scalar type. The
@@ -336,7 +334,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
             PassMode::Cast(cast, _) => cast.llvm_type(cx),
             PassMode::Indirect { .. } => {
-                llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
+                llargument_tys.push(cx.type_ptr());
                 cx.type_void()
             }
         };
@@ -364,9 +362,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     }
                     cast.llvm_type(cx)
                 }
-                PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
-                    cx.type_ptr_to(arg.memory_ty(cx))
-                }
+                PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
             };
             llargument_tys.push(llarg_ty);
         }
@@ -379,12 +375,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
     }
 
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
-        unsafe {
-            llvm::LLVMPointerType(
-                self.llvm_type(cx),
-                cx.data_layout().instruction_address_space.0 as c_uint,
-            )
-        }
+        cx.type_ptr_ext(cx.data_layout().instruction_address_space)
     }
 
     fn llvm_cconv(&self) -> llvm::CallConv {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index a57508815d6..ca123334fca 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -28,7 +28,7 @@ pub(crate) unsafe fn codegen(
         tws => bug!("Unsupported target word size for int: {}", tws),
     };
     let i8 = llvm::LLVMInt8TypeInContext(llcx);
-    let i8p = llvm::LLVMPointerType(i8, 0);
+    let i8p = llvm::LLVMPointerTypeInContext(llcx, 0);
     let void = llvm::LLVMVoidTypeInContext(llcx);
 
     if kind == AllocatorKind::Default {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 4c69b9503a2..4c9094bf1f5 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -363,50 +363,44 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
         || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
     {
-        if llvm_util::get_version() >= (15, 0, 0) {
-            to_add.push(create_alloc_family_attr(cx.llcx));
-            // apply to argument place instead of function
-            let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
-            attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
-            to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
-            let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
-            if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
-                flags |= AllocKindFlags::Uninitialized;
-            } else {
-                flags |= AllocKindFlags::Zeroed;
-            }
-            to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
+        to_add.push(create_alloc_family_attr(cx.llcx));
+        // apply to argument place instead of function
+        let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
+        to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
+        let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
+            flags |= AllocKindFlags::Uninitialized;
+        } else {
+            flags |= AllocKindFlags::Zeroed;
         }
+        to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
         // apply to return place instead of function (unlike all other attributes applied in this function)
         let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
         attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
     }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
-        if llvm_util::get_version() >= (15, 0, 0) {
-            to_add.push(create_alloc_family_attr(cx.llcx));
-            to_add.push(llvm::CreateAllocKindAttr(
-                cx.llcx,
-                AllocKindFlags::Realloc | AllocKindFlags::Aligned,
-            ));
-            // applies to argument place instead of function place
-            let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
-            attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
-            // apply to argument place instead of function
-            let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
-            attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
-            to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
-        }
+        to_add.push(create_alloc_family_attr(cx.llcx));
+        to_add.push(llvm::CreateAllocKindAttr(
+            cx.llcx,
+            AllocKindFlags::Realloc | AllocKindFlags::Aligned,
+        ));
+        // applies to argument place instead of function place
+        let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
+        // apply to argument place instead of function
+        let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
+        to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
         let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
         attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
     }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
-        if llvm_util::get_version() >= (15, 0, 0) {
-            to_add.push(create_alloc_family_attr(cx.llcx));
-            to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
-            // applies to argument place instead of function place
-            let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
-            attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
-        }
+        to_add.push(create_alloc_family_attr(cx.llcx));
+        to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
+        // applies to argument place instead of function place
+        let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
     }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
         to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
@@ -450,7 +444,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     let mut function_features = function_features
         .iter()
         .flat_map(|feat| {
-            llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{}", f))
+            llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{f}"))
         })
         .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
             InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 10bf954d242..a82d2c5771a 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -56,7 +56,7 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
         "x86" => LLVMMachineType::I386,
         "aarch64" => LLVMMachineType::ARM64,
         "arm" => LLVMMachineType::ARM,
-        _ => panic!("unsupported cpu type {}", cpu),
+        _ => panic!("unsupported cpu type {cpu}"),
     }
 }
 
@@ -128,7 +128,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
         let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
         let output_path = {
             let mut output_path: PathBuf = tmpdir.to_path_buf();
-            output_path.push(format!("{}{}", lib_name, name_suffix));
+            output_path.push(format!("{lib_name}{name_suffix}"));
             output_path.with_extension("lib")
         };
 
@@ -156,7 +156,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             // functions. Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
             let def_file_path =
-                tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
+                tmpdir.join(format!("{lib_name}{name_suffix}")).with_extension("def");
 
             let def_file_content = format!(
                 "EXPORTS\n{}",
@@ -164,7 +164,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                     .into_iter()
                     .map(|(name, ordinal)| {
                         match ordinal {
-                            Some(n) => format!("{} @{} NONAME", name, n),
+                            Some(n) => format!("{name} @{n} NONAME"),
                             None => name,
                         }
                     })
@@ -435,7 +435,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
 }
 
 fn string_to_io_error(s: String) -> io::Error {
-    io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
+    io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
 }
 
 fn find_binutils_dlltool(sess: &Session) -> OsString {
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index d7dd98d7938..b2d28cef899 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -7,7 +7,7 @@ use crate::{LlvmCodegenBackend, ModuleLlvm};
 use object::read::archive::ArchiveFile;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
-use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig};
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, TargetMachineFactoryConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::FxHashMap;
@@ -166,7 +166,7 @@ fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFro
 /// for further optimization.
 pub(crate) fn run_fat(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
+    modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
 ) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> {
     let diag_handler = cgcx.create_diag_handler();
@@ -220,7 +220,7 @@ pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBu
 fn fat_lto(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
-    modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
+    modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     symbols_below_threshold: &[*const libc::c_char],
@@ -245,8 +245,8 @@ fn fat_lto(
     }));
     for module in modules {
         match module {
-            FatLTOInput::InMemory(m) => in_memory.push(m),
-            FatLTOInput::Serialized { name, buffer } => {
+            FatLtoInput::InMemory(m) => in_memory.push(m),
+            FatLtoInput::Serialized { name, buffer } => {
                 info!("pushing serialized module {:?}", name);
                 let buffer = SerializedModule::Local(buffer);
                 serialized_modules.push((buffer, CString::new(name).unwrap()));
@@ -332,7 +332,7 @@ fn fat_lto(
             let _timer = cgcx
                 .prof
                 .generic_activity_with_arg_recorder("LLVM_fat_lto_link_module", |recorder| {
-                    recorder.record_arg(format!("{:?}", name))
+                    recorder.record_arg(format!("{name:?}"))
                 });
             info!("linking {:?}", name);
             let data = bc_decoded.data();
@@ -787,7 +787,7 @@ impl ThinLTOKeysMap {
         let file = File::create(path)?;
         let mut writer = io::BufWriter::new(file);
         for (module, key) in &self.keys {
-            writeln!(writer, "{} {}", module, key)?;
+            writeln!(writer, "{module} {key}")?;
         }
         Ok(())
     }
@@ -801,7 +801,7 @@ impl ThinLTOKeysMap {
             let mut split = line.split(' ');
             let module = split.next().unwrap();
             let key = split.next().unwrap();
-            assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line);
+            assert_eq!(split.next(), None, "Expected two space-separated values, found {line:?}");
             keys.insert(module.to_string(), key.to_string());
         }
         Ok(Self { keys })
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 0f5e975445f..46e6daed21f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -4,7 +4,6 @@ use crate::back::profiling::{
 };
 use crate::base;
 use crate::common;
-use crate::consts;
 use crate::errors::{
     CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
 };
@@ -259,7 +258,7 @@ pub(crate) fn save_temp_bitcode(
         return;
     }
     unsafe {
-        let ext = format!("{}.bc", name);
+        let ext = format!("{name}.bc");
         let cgu = Some(&module.name[..]);
         let path = cgcx.output_filenames.temp_path_ext(&ext, cgu);
         let cstr = path_to_c_string(&path);
@@ -382,29 +381,22 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
         }
 
         llvm::diagnostic::Optimization(opt) => {
-            let enabled = match cgcx.remark {
-                Passes::All => true,
-                Passes::Some(ref v) => v.iter().any(|s| *s == opt.pass_name),
-            };
-
-            if enabled {
-                diag_handler.emit_note(FromLlvmOptimizationDiag {
-                    filename: &opt.filename,
-                    line: opt.line,
-                    column: opt.column,
-                    pass_name: &opt.pass_name,
-                    kind: match opt.kind {
-                        OptimizationDiagnosticKind::OptimizationRemark => "success",
-                        OptimizationDiagnosticKind::OptimizationMissed
-                        | OptimizationDiagnosticKind::OptimizationFailure => "missed",
-                        OptimizationDiagnosticKind::OptimizationAnalysis
-                        | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute
-                        | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis",
-                        OptimizationDiagnosticKind::OptimizationRemarkOther => "other",
-                    },
-                    message: &opt.message,
-                });
-            }
+            diag_handler.emit_note(FromLlvmOptimizationDiag {
+                filename: &opt.filename,
+                line: opt.line,
+                column: opt.column,
+                pass_name: &opt.pass_name,
+                kind: match opt.kind {
+                    OptimizationDiagnosticKind::OptimizationRemark => "success",
+                    OptimizationDiagnosticKind::OptimizationMissed
+                    | OptimizationDiagnosticKind::OptimizationFailure => "missed",
+                    OptimizationDiagnosticKind::OptimizationAnalysis
+                    | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute
+                    | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis",
+                    OptimizationDiagnosticKind::OptimizationRemarkOther => "other",
+                },
+                message: &opt.message,
+            });
         }
         llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => {
             let message = llvm::build_string(|s| {
@@ -713,7 +705,7 @@ pub(crate) unsafe fn codegen(
 
                 let Ok(demangled) = rustc_demangle::try_demangle(input) else { return 0 };
 
-                if write!(cursor, "{:#}", demangled).is_err() {
+                if write!(cursor, "{demangled:#}").is_err() {
                     // Possible only if provided buffer is not big enough
                     return 0;
                 }
@@ -834,7 +826,7 @@ pub(crate) unsafe fn codegen(
 }
 
 fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: &[u8]) -> Vec<u8> {
-    let mut asm = format!(".section {},\"{}\"\n", section_name, section_flags).into_bytes();
+    let mut asm = format!(".section {section_name},\"{section_flags}\"\n").into_bytes();
     asm.extend_from_slice(b".ascii \"");
     asm.reserve(data.len());
     for &byte in data {
@@ -992,7 +984,7 @@ fn create_msvc_imps(
     let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" };
 
     unsafe {
-        let i8p_ty = Type::i8p_llcx(llcx);
+        let ptr_ty = Type::ptr_llcx(llcx);
         let globals = base::iter_globals(llmod)
             .filter(|&val| {
                 llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
@@ -1012,8 +1004,8 @@ fn create_msvc_imps(
             .collect::<Vec<_>>();
 
         for (imp_name, val) in globals {
-            let imp = llvm::LLVMAddGlobal(llmod, i8p_ty, imp_name.as_ptr().cast());
-            llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
+            let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr().cast());
+            llvm::LLVMSetInitializer(imp, val);
             llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 5b5f81c0329..b659fd02eec 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -123,8 +123,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen
             // happen after the llvm.used variables are created.
             for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
                 unsafe {
-                    let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
-                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
+                    llvm::LLVMReplaceAllUsesWith(old_g, new_g);
                     llvm::LLVMDeleteGlobal(old_g);
                 }
             }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index d55992bf092..5408481df48 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -652,7 +652,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         flags: MemFlags,
     ) -> &'ll Value {
         debug!("Store {:?} -> {:?} ({:?})", val, ptr, flags);
-        let ptr = self.check_store(val, ptr);
+        assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer);
         unsafe {
             let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
             let align =
@@ -682,7 +682,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         size: Size,
     ) {
         debug!("Store {:?} -> {:?}", val, ptr);
-        let ptr = self.check_store(val, ptr);
+        assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer);
         unsafe {
             let store = llvm::LLVMRustBuildAtomicStore(
                 self.llbuilder,
@@ -873,8 +873,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
         let size = self.intcast(size, self.type_isize(), false);
         let is_volatile = flags.contains(MemFlags::VOLATILE);
-        let dst = self.pointercast(dst, self.type_i8p());
-        let src = self.pointercast(src, self.type_i8p());
         unsafe {
             llvm::LLVMRustBuildMemCpy(
                 self.llbuilder,
@@ -900,8 +898,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported");
         let size = self.intcast(size, self.type_isize(), false);
         let is_volatile = flags.contains(MemFlags::VOLATILE);
-        let dst = self.pointercast(dst, self.type_i8p());
-        let src = self.pointercast(src, self.type_i8p());
         unsafe {
             llvm::LLVMRustBuildMemMove(
                 self.llbuilder,
@@ -924,7 +920,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         flags: MemFlags,
     ) {
         let is_volatile = flags.contains(MemFlags::VOLATILE);
-        let ptr = self.pointercast(ptr, self.type_i8p());
         unsafe {
             llvm::LLVMRustBuildMemSet(
                 self.llbuilder,
@@ -981,7 +976,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
-        let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
+        let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false);
         let landing_pad = self.landing_pad(ty, pers_fn, 0);
         unsafe {
             llvm::LLVMSetCleanup(landing_pad, llvm::True);
@@ -990,14 +985,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
-        let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
+        let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false);
         let landing_pad = self.landing_pad(ty, pers_fn, 1);
-        self.add_clause(landing_pad, self.const_array(self.type_i8p(), &[]));
+        self.add_clause(landing_pad, self.const_array(self.type_ptr(), &[]));
         (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
     }
 
     fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
-        let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
+        let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false);
         let mut exn = self.const_poison(ty);
         exn = self.insert_value(exn, exn0, 0);
         exn = self.insert_value(exn, exn1, 1);
@@ -1161,7 +1156,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
         let llty = self.cx.type_func(
-            &[self.cx.type_i8p(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
+            &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
             self.cx.type_void(),
         );
         let args = &[fn_name, hash, num_counters, index];
@@ -1387,25 +1382,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         ret.expect("LLVM does not have support for catchret")
     }
 
-    fn check_store(&mut self, val: &'ll Value, ptr: &'ll Value) -> &'ll Value {
-        let dest_ptr_ty = self.cx.val_ty(ptr);
-        let stored_ty = self.cx.val_ty(val);
-        let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
-
-        assert_eq!(self.cx.type_kind(dest_ptr_ty), TypeKind::Pointer);
-
-        if dest_ptr_ty == stored_ptr_ty {
-            ptr
-        } else {
-            debug!(
-                "type mismatch in store. \
-                    Expected {:?}, got {:?}; inserting bitcast",
-                dest_ptr_ty, stored_ptr_ty
-            );
-            self.bitcast(ptr, stored_ptr_ty)
-        }
-    }
-
     fn check_call<'b>(
         &mut self,
         typ: &str,
@@ -1415,9 +1391,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     ) -> Cow<'b, [&'ll Value]> {
         assert!(
             self.cx.type_kind(fn_ty) == TypeKind::Function,
-            "builder::{} not passed a function, but {:?}",
-            typ,
-            fn_ty
+            "builder::{typ} not passed a function, but {fn_ty:?}"
         );
 
         let param_tys = self.cx.func_params_types(fn_ty);
@@ -1468,7 +1442,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             return;
         }
 
-        let ptr = self.pointercast(ptr, self.cx.type_i8p());
         self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
     }
 
@@ -1509,12 +1482,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         let instr = if signed { "fptosi" } else { "fptoui" };
         let name = if let Some(vector_length) = vector_length {
-            format!(
-                "llvm.{}.sat.v{}i{}.v{}f{}",
-                instr, vector_length, int_width, vector_length, float_width
-            )
+            format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}")
         } else {
-            format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
+            format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
         };
         let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
         self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None)
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 5d3e245f45f..36c098218cf 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -4,13 +4,11 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use crate::abi::FnAbiLlvmExt;
 use crate::attributes;
 use crate::common;
 use crate::context::CodegenCx;
 use crate::llvm;
 use crate::value::Value;
-use rustc_codegen_ssa::traits::*;
 
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
@@ -45,39 +43,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
     let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
     let llfn = if let Some(llfn) = cx.get_declared_value(sym) {
-        // Create a fn pointer with the new signature.
-        let llptrty = fn_abi.ptr_to_llvm_type(cx);
-
-        // This is subtle and surprising, but sometimes we have to bitcast
-        // the resulting fn pointer. The reason has to do with external
-        // functions. If you have two crates that both bind the same C
-        // library, they may not use precisely the same types: for
-        // example, they will probably each declare their own structs,
-        // which are distinct types from LLVM's point of view (nominal
-        // types).
-        //
-        // Now, if those two crates are linked into an application, and
-        // they contain inlined code, you can wind up with a situation
-        // where both of those functions wind up being loaded into this
-        // application simultaneously. In that case, the same function
-        // (from LLVM's point of view) requires two types. But of course
-        // LLVM won't allow one function to have two types.
-        //
-        // What we currently do, therefore, is declare the function with
-        // one of the two types (whichever happens to come first) and then
-        // bitcast as needed when the function is referenced to make sure
-        // it has the type we expect.
-        //
-        // This can occur on either a crate-local or crate-external
-        // reference. It also occurs when testing libcore and in some
-        // other weird situations. Annoying.
-        if cx.val_ty(llfn) != llptrty {
-            debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
-            cx.const_ptrcast(llfn, llptrty)
-        } else {
-            debug!("get_fn: not casting pointer!");
-            llfn
-        }
+        llfn
     } else {
         let instance_def_id = instance.def_id();
         let llfn = if tcx.sess.target.arch == "x86" &&
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 4d879fbdcb7..0b0816c27b6 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -1,10 +1,9 @@
 //! Code that is useful in various codegen modules.
 
-use crate::consts::{self, const_alloc_to_llvm};
+use crate::consts::const_alloc_to_llvm;
 pub use crate::context::CodegenCx;
 use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, OperandBundleDef, True};
 use crate::type_::Type;
-use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 
 use rustc_ast::Mutability;
@@ -13,7 +12,6 @@ use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer};
@@ -211,11 +209,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             })
             .1;
         let len = s.len();
-        let cs = consts::ptrcast(
-            str_global,
-            self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
-        );
-        (cs, self.const_usize(len as u64))
+        (str_global, self.const_usize(len as u64))
     }
 
     fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
@@ -292,7 +286,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 let llval = unsafe {
                     llvm::LLVMConstInBoundsGEP2(
                         self.type_i8(),
-                        self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
+                        self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)),
                         &self.const_usize(offset.bytes()),
                         1,
                     )
@@ -310,10 +304,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         const_alloc_to_llvm(self, alloc)
     }
 
-    fn const_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-        consts::ptrcast(val, ty)
-    }
-
     fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
         self.const_bitcast(val, ty)
     }
@@ -322,7 +312,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe {
             llvm::LLVMConstInBoundsGEP2(
                 self.type_i8(),
-                self.const_bitcast(base_addr, self.type_i8p()),
+                base_addr,
                 &self.const_usize(offset.bytes()),
                 1,
             )
@@ -420,10 +410,10 @@ pub(crate) fn i686_decorated_name(
             DllCallingConvention::C => {}
             DllCallingConvention::Stdcall(arg_list_size)
             | DllCallingConvention::Fastcall(arg_list_size) => {
-                write!(&mut decorated_name, "@{}", arg_list_size).unwrap();
+                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
             }
             DllCallingConvention::Vectorcall(arg_list_size) => {
-                write!(&mut decorated_name, "@@{}", arg_list_size).unwrap();
+                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index df52f50f86f..95af2f8ef4a 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -103,7 +103,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
                 value: Primitive::Pointer(address_space),
                 valid_range: WrappingRange::full(dl.pointer_size),
             },
-            cx.type_i8p_ext(address_space),
+            cx.type_ptr_ext(address_space),
         ));
         next_offset = offset + pointer_size;
     }
@@ -179,7 +179,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
                 })
             });
             llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-            llvm::LLVMSetInitializer(g2, cx.const_ptrcast(g1, llty));
+            llvm::LLVMSetInitializer(g2, g1);
             g2
         }
     } else if cx.tcx.sess.target.arch == "x86" &&
@@ -193,10 +193,6 @@ fn check_and_apply_linkage<'ll, 'tcx>(
     }
 }
 
-pub fn ptrcast<'ll>(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-    unsafe { llvm::LLVMConstPointerCast(val, ty) }
-}
-
 impl<'ll> CodegenCx<'ll, '_> {
     pub(crate) fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMConstBitCast(val, ty) }
@@ -238,8 +234,7 @@ impl<'ll> CodegenCx<'ll, '_> {
         assert!(
             !defined_in_current_codegen_unit,
             "consts::get_static() should always hit the cache for \
-                 statics defined in the same CGU, but did not for `{:?}`",
-            def_id
+                 statics defined in the same CGU, but did not for `{def_id:?}`"
         );
 
         let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
@@ -251,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> {
         let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
             let llty = self.layout_of(ty).llvm_type(self);
             if let Some(g) = self.get_declared_value(sym) {
-                if self.val_ty(g) != self.type_ptr_to(llty) {
+                if self.val_ty(g) != self.type_ptr() {
                     span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
                 }
             }
@@ -552,16 +547,14 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
         }
     }
 
-    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of ptr.
     fn add_used_global(&self, global: &'ll Value) {
-        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
-        self.used_statics.borrow_mut().push(cast);
+        self.used_statics.borrow_mut().push(global);
     }
 
     /// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
-    /// an array of i8*.
+    /// an array of ptr.
     fn add_compiler_used_global(&self, global: &'ll Value) {
-        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
-        self.compiler_used_statics.borrow_mut().push(cast);
+        self.compiler_used_statics.borrow_mut().push(global);
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 5bf641055c5..cb093996d1d 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -59,17 +59,6 @@ pub struct CodegenCx<'ll, 'tcx> {
     /// Cache of constant strings,
     pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>,
 
-    /// Reverse-direction for const ptrs cast from globals.
-    ///
-    /// Key is a Value holding a `*T`,
-    /// Val is a Value holding a `*[T]`.
-    ///
-    /// Needed because LLVM loses pointer->pointee association
-    /// when we ptrcast, and we have to ptrcast during codegen
-    /// of a `[T]` const because we form a slice, a `(*T,usize)` pair, not
-    /// a pointer to an LLVM array type. Similar for trait objects.
-    pub const_unsized: RefCell<FxHashMap<&'ll Value, &'ll Value>>,
-
     /// Cache of emitted const globals (value -> global)
     pub const_globals: RefCell<FxHashMap<&'ll Value, &'ll Value>>,
 
@@ -464,7 +453,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             instances: Default::default(),
             vtables: Default::default(),
             const_str_cache: Default::default(),
-            const_unsized: Default::default(),
             const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
             used_statics: RefCell::new(Vec::new()),
@@ -495,7 +483,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
     pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
         let section = cstr!("llvm.metadata");
-        let array = self.const_array(self.type_ptr_to(self.type_i8()), values);
+        let array = self.const_array(self.type_ptr(), values);
 
         unsafe {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
@@ -673,7 +661,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             ($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false))
         }
 
-        let i8p = self.type_i8p();
+        let ptr = self.type_ptr();
         let void = self.type_void();
         let i1 = self.type_i1();
         let t_i8 = self.type_i8();
@@ -687,7 +675,7 @@ impl<'ll> CodegenCx<'ll, '_> {
         let t_metadata = self.type_metadata();
         let t_token = self.type_token();
 
-        ifn!("llvm.wasm.get.exception", fn(t_token) -> i8p);
+        ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr);
         ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32);
 
         ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
@@ -723,7 +711,7 @@ impl<'ll> CodegenCx<'ll, '_> {
 
         ifn!("llvm.trap", fn() -> void);
         ifn!("llvm.debugtrap", fn() -> void);
-        ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
+        ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
 
         ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
         ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
@@ -890,43 +878,43 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
         ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
 
-        ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
-        ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
+        ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void);
+        ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void);
 
         ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
-        ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
+        ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32);
         ifn!("llvm.localescape", fn(...) -> void);
-        ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p);
-        ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p);
+        ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr);
+        ifn!("llvm.x86.seh.recoverfp", fn(ptr, ptr) -> ptr);
 
         ifn!("llvm.assume", fn(i1) -> void);
-        ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
+        ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void);
 
         // This isn't an "LLVM intrinsic", but LLVM's optimization passes
         // recognize it like one and we assume it exists in `core::slice::cmp`
         match self.sess().target.arch.as_ref() {
-            "avr" | "msp430" => ifn!("memcmp", fn(i8p, i8p, t_isize) -> t_i16),
-            _ => ifn!("memcmp", fn(i8p, i8p, t_isize) -> t_i32),
+            "avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16),
+            _ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32),
         }
 
         // variadic intrinsics
-        ifn!("llvm.va_start", fn(i8p) -> void);
-        ifn!("llvm.va_end", fn(i8p) -> void);
-        ifn!("llvm.va_copy", fn(i8p, i8p) -> void);
+        ifn!("llvm.va_start", fn(ptr) -> void);
+        ifn!("llvm.va_end", fn(ptr) -> void);
+        ifn!("llvm.va_copy", fn(ptr, ptr) -> void);
 
         if self.sess().instrument_coverage() {
-            ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
+            ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void);
         }
 
-        ifn!("llvm.type.test", fn(i8p, t_metadata) -> i1);
-        ifn!("llvm.type.checked.load", fn(i8p, t_i32, t_metadata) -> mk_struct! {i8p, i1});
+        ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1);
+        ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1});
 
         if self.sess().opts.debuginfo != DebugInfo::None {
             ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
             ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
         }
 
-        ifn!("llvm.ptrmask", fn(i8p, t_isize) -> i8p);
+        ifn!("llvm.ptrmask", fn(ptr, t_isize) -> ptr);
 
         None
     }
@@ -940,12 +928,10 @@ impl<'ll> CodegenCx<'ll, '_> {
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
-                let ty = self
-                    .type_struct(&[self.type_ptr_to(self.type_isize()), self.type_i8p()], false);
+                let ty = self.type_struct(&[self.type_ptr(), self.type_ptr()], false);
                 self.declare_global("rust_eh_catch_typeinfo", ty)
             }
         };
-        let eh_catch_typeinfo = self.const_bitcast(eh_catch_typeinfo, self.type_i8p());
         self.eh_catch_typeinfo.set(Some(eh_catch_typeinfo));
         eh_catch_typeinfo
     }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 1791ce4b315..6ca61aa43d7 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
+use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex};
 
 /// Must match the layout of `LLVMRustCounterKind`.
 #[derive(Copy, Clone, Debug)]
@@ -36,11 +36,9 @@ impl Counter {
         Self { kind: CounterKind::Zero, id: 0 }
     }
 
-    /// Constructs a new `Counter` of kind `CounterValueReference`, and converts
-    /// the given 1-based counter_id to the required 0-based equivalent for
-    /// the `Counter` encoding.
-    pub fn counter_value_reference(counter_id: CounterValueReference) -> Self {
-        Self { kind: CounterKind::CounterValueReference, id: counter_id.zero_based_index() }
+    /// Constructs a new `Counter` of kind `CounterValueReference`.
+    pub fn counter_value_reference(counter_id: CounterId) -> Self {
+        Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
     }
 
     /// Constructs a new `Counter` of kind `Expression`.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 06844afd6b8..7e981af0a53 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -3,24 +3,22 @@ pub use super::ffi::*;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::bug;
 use rustc_middle::mir::coverage::{
-    CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
-    InjectedExpressionIndex, MappedExpressionIndex, Op,
+    CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand,
 };
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
 
 #[derive(Clone, Debug, PartialEq)]
 pub struct Expression {
-    lhs: ExpressionOperandId,
+    lhs: Operand,
     op: Op,
-    rhs: ExpressionOperandId,
+    rhs: Operand,
     region: Option<CodeRegion>,
 }
 
 /// Collects all of the coverage regions associated with (a) injected counters, (b) counter
 /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
-/// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
-/// can both be operands in an expression. This struct also stores the `function_source_hash`,
+/// for a given Function. This struct also stores the `function_source_hash`,
 /// computed during instrumentation, and forwarded with counters.
 ///
 /// Note, it may be important to understand LLVM's definitions of `unreachable` regions versus "gap
@@ -34,8 +32,8 @@ pub struct FunctionCoverage<'tcx> {
     instance: Instance<'tcx>,
     source_hash: u64,
     is_used: bool,
-    counters: IndexVec<CounterValueReference, Option<CodeRegion>>,
-    expressions: IndexVec<InjectedExpressionIndex, Option<Expression>>,
+    counters: IndexVec<CounterId, Option<CodeRegion>>,
+    expressions: IndexVec<ExpressionId, Option<Expression>>,
     unreachable_regions: Vec<CodeRegion>,
 }
 
@@ -82,48 +80,36 @@ impl<'tcx> FunctionCoverage<'tcx> {
     }
 
     /// Adds a code region to be counted by an injected counter intrinsic.
-    pub fn add_counter(&mut self, id: CounterValueReference, region: CodeRegion) {
+    pub fn add_counter(&mut self, id: CounterId, region: CodeRegion) {
         if let Some(previous_region) = self.counters[id].replace(region.clone()) {
             assert_eq!(previous_region, region, "add_counter: code region for id changed");
         }
     }
 
     /// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
-    /// expressions. Expression IDs start from `u32::MAX` and go down, so the range of expression
-    /// IDs will not overlap with the range of counter IDs. Counters and expressions can be added in
-    /// any order, and expressions can still be assigned contiguous (though descending) IDs, without
-    /// knowing what the last counter ID will be.
-    ///
-    /// When storing the expression data in the `expressions` vector in the `FunctionCoverage`
-    /// struct, its vector index is computed, from the given expression ID, by subtracting from
-    /// `u32::MAX`.
-    ///
-    /// Since the expression operands (`lhs` and `rhs`) can reference either counters or
-    /// expressions, an operand that references an expression also uses its original ID, descending
-    /// from `u32::MAX`. Theses operands are translated only during code generation, after all
-    /// counters and expressions have been added.
+    /// expressions. These are tracked as separate variants of `Operand`, so there is no ambiguity
+    /// between operands that are counter IDs and operands that are expression IDs.
     pub fn add_counter_expression(
         &mut self,
-        expression_id: InjectedExpressionId,
-        lhs: ExpressionOperandId,
+        expression_id: ExpressionId,
+        lhs: Operand,
         op: Op,
-        rhs: ExpressionOperandId,
+        rhs: Operand,
         region: Option<CodeRegion>,
     ) {
         debug!(
             "add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}",
             expression_id, lhs, op, rhs, region
         );
-        let expression_index = self.expression_index(u32::from(expression_id));
         debug_assert!(
-            expression_index.as_usize() < self.expressions.len(),
-            "expression_index {} is out of range for expressions.len() = {}
+            expression_id.as_usize() < self.expressions.len(),
+            "expression_id {} is out of range for expressions.len() = {}
             for {:?}",
-            expression_index.as_usize(),
+            expression_id.as_usize(),
             self.expressions.len(),
             self,
         );
-        if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
+        if let Some(previous_expression) = self.expressions[expression_id].replace(Expression {
             lhs,
             op,
             rhs,
@@ -186,14 +172,11 @@ impl<'tcx> FunctionCoverage<'tcx> {
 
         // This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
         // `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
-        // and value. Operand ID value `0` maps to `CounterKind::Zero`; values in the known range
-        // of injected LLVM counters map to `CounterKind::CounterValueReference` (and the value
-        // matches the injected counter index); and any other value is converted into a
-        // `CounterKind::Expression` with the expression's `new_index`.
+        // and value.
         //
         // Expressions will be returned from this function in a sequential vector (array) of
         // `CounterExpression`, so the expression IDs must be mapped from their original,
-        // potentially sparse set of indexes, originally in reverse order from `u32::MAX`.
+        // potentially sparse set of indexes.
         //
         // An `Expression` as an operand will have already been encountered as an `Expression` with
         // operands, so its new_index will already have been generated (as a 1-up index value).
@@ -206,34 +189,19 @@ impl<'tcx> FunctionCoverage<'tcx> {
         // `expression_index`s lower than the referencing `Expression`. Therefore, it is
         // reasonable to look up the new index of an expression operand while the `new_indexes`
         // vector is only complete up to the current `ExpressionIndex`.
-        let id_to_counter = |new_indexes: &IndexSlice<
-            InjectedExpressionIndex,
-            Option<MappedExpressionIndex>,
-        >,
-                             id: ExpressionOperandId| {
-            if id == ExpressionOperandId::ZERO {
-                Some(Counter::zero())
-            } else if id.index() < self.counters.len() {
-                debug_assert!(
-                    id.index() > 0,
-                    "ExpressionOperandId indexes for counters are 1-based, but this id={}",
-                    id.index()
-                );
-                // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
-                // and may not have their own `CodeRegion`s,
-                let index = CounterValueReference::from(id.index());
-                // Note, the conversion to LLVM `Counter` adjusts the index to be zero-based.
-                Some(Counter::counter_value_reference(index))
-            } else {
-                let index = self.expression_index(u32::from(id));
+        type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>;
+        let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
+            Operand::Zero => Some(Counter::zero()),
+            Operand::Counter(id) => Some(Counter::counter_value_reference(id)),
+            Operand::Expression(id) => {
                 self.expressions
-                    .get(index)
+                    .get(id)
                     .expect("expression id is out of range")
                     .as_ref()
                     // If an expression was optimized out, assume it would have produced a count
                     // of zero. This ensures that expressions dependent on optimized-out
                     // expressions are still valid.
-                    .map_or(Some(Counter::zero()), |_| new_indexes[index].map(Counter::expression))
+                    .map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression))
             }
         };
 
@@ -340,9 +308,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
     fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
         self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
     }
-
-    fn expression_index(&self, id_descending_from_max: u32) -> InjectedExpressionIndex {
-        debug_assert!(id_descending_from_max >= self.counters.len() as u32);
-        InjectedExpressionIndex::from(u32::MAX - id_descending_from_max)
-    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 60cbb3d3d9d..c1017ab8d7c 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -16,9 +16,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_llvm::RustString;
 use rustc_middle::bug;
-use rustc_middle::mir::coverage::{
-    CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
-};
+use rustc_middle::mir::coverage::{CodeRegion, CounterId, CoverageKind, ExpressionId, Op, Operand};
 use rustc_middle::mir::Coverage;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
@@ -33,7 +31,7 @@ mod ffi;
 pub(crate) mod map_data;
 pub mod mapgen;
 
-const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
+const UNUSED_FUNCTION_COUNTER_ID: CounterId = CounterId::START;
 
 const VAR_ALIGN_BYTES: usize = 8;
 
@@ -125,7 +123,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
                     let fn_name = bx.get_pgo_func_name_var(instance);
                     let hash = bx.const_u64(function_source_hash);
                     let num_counters = bx.const_u32(coverageinfo.num_counters);
-                    let index = bx.const_u32(id.zero_based_index());
+                    let index = bx.const_u32(id.as_u32());
                     debug!(
                         "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
                         fn_name, hash, num_counters, index,
@@ -178,7 +176,7 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
     fn add_coverage_counter(
         &mut self,
         instance: Instance<'tcx>,
-        id: CounterValueReference,
+        id: CounterId,
         region: CodeRegion,
     ) -> bool {
         if let Some(coverage_context) = self.coverage_context() {
@@ -202,10 +200,10 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
     fn add_coverage_counter_expression(
         &mut self,
         instance: Instance<'tcx>,
-        id: InjectedExpressionId,
-        lhs: ExpressionOperandId,
+        id: ExpressionId,
+        lhs: Operand,
         op: Op,
-        rhs: ExpressionOperandId,
+        rhs: Operand,
         region: Option<CodeRegion>,
     ) -> bool {
         if let Some(coverage_context) = self.coverage_context() {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 37f30917609..ef7c661936a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -17,8 +17,7 @@ use rustc_span::symbol::sym;
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
 pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
     if needs_gdb_debug_scripts_section(bx) {
-        let gdb_debug_scripts_section =
-            bx.const_bitcast(get_or_insert_gdb_debug_scripts_section_global(bx), bx.type_i8p());
+        let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
         // Load just the first byte as that's all that's necessary to force
         // LLVM to keep around the reference to the global.
         let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
@@ -54,7 +53,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
             // The initial byte `4` instructs GDB that the following pretty printer
             // is defined inline as opposed to in a standalone file.
             section_contents.extend_from_slice(b"\x04");
-            let vis_name = format!("pretty-printer-{}-{}\n", crate_name, index);
+            let vis_name = format!("pretty-printer-{crate_name}-{index}\n");
             section_contents.extend_from_slice(vis_name.as_bytes());
             section_contents.extend_from_slice(&visualizer.src);
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 905e0e541a8..40f0bcfdf58 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -184,9 +184,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
             debug_assert_eq!(
                 (data_layout.pointer_size, data_layout.pointer_align.abi),
                 cx.size_and_align_of(ptr_type),
-                "ptr_type={}, pointee_type={}",
-                ptr_type,
-                pointee_type,
+                "ptr_type={ptr_type}, pointee_type={pointee_type}",
             );
 
             let di_node = unsafe {
@@ -521,7 +519,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
 fn hex_encode(data: &[u8]) -> String {
     let mut hex_string = String::with_capacity(data.len() * 2);
     for byte in data.iter() {
-        write!(&mut hex_string, "{:02x}", byte).unwrap();
+        write!(&mut hex_string, "{byte:02x}").unwrap();
     }
     hex_string
 }
@@ -766,7 +764,7 @@ fn build_param_type_di_node<'ll, 'tcx>(
     t: Ty<'tcx>,
 ) -> DINodeCreationResult<'ll> {
     debug!("build_param_type_di_node: {:?}", t);
-    let name = format!("{:?}", t);
+    let name = format!("{t:?}");
     DINodeCreationResult {
         di_node: unsafe {
             llvm::LLVMRustDIBuilderCreateBasicType(
@@ -814,7 +812,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
     debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo);
     let rustc_producer = format!("rustc version {}", tcx.sess.cfg_version);
     // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
-    let producer = format!("clang LLVM ({})", rustc_producer);
+    let producer = format!("clang LLVM ({rustc_producer})");
 
     let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
     let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped);
@@ -1331,10 +1329,10 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
                             // Note: This code does not try to give a proper name to each method
                             //       because their might be multiple methods with the same name
                             //       (coming from different traits).
-                            (format!("__method{}", index), void_pointer_type_di_node)
+                            (format!("__method{index}"), void_pointer_type_di_node)
                         }
                         ty::VtblEntry::TraitVPtr(_) => {
-                            (format!("__super_trait_ptr{}", index), void_pointer_type_di_node)
+                            (format!("__super_trait_ptr{index}"), void_pointer_type_di_node)
                         }
                         ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_di_node),
                         ty::VtblEntry::MetadataSize => ("size".to_string(), usize_di_node),
@@ -1504,5 +1502,5 @@ pub fn tuple_field_name(field_index: usize) -> Cow<'static, str> {
     TUPLE_FIELD_NAMES
         .get(field_index)
         .map(|s| Cow::from(*s))
-        .unwrap_or_else(|| Cow::from(format!("__{}", field_index)))
+        .unwrap_or_else(|| Cow::from(format!("__{field_index}")))
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 7be83638676..c758010c581 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -91,8 +91,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
             // For all other pointee types we should already have returned None
             // at the beginning of the function.
             panic!(
-                "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {:?}",
-                pointee_tail_ty
+                "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
             )
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 6df1b708ccd..86c39ab5e94 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -167,7 +167,6 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 let ptr = args[0].immediate();
                 let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
                     let llty = ty.llvm_type(self);
-                    let ptr = self.pointercast(ptr, self.type_ptr_to(llty));
                     self.volatile_load(llty, ptr)
                 } else {
                     self.volatile_load(self.layout_of(tp_ty).llvm_type(self), ptr)
@@ -230,22 +229,22 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                         sym::ctlz | sym::cttz => {
                             let y = self.const_bool(false);
                             self.call_intrinsic(
-                                &format!("llvm.{}.i{}", name, width),
+                                &format!("llvm.{name}.i{width}"),
                                 &[args[0].immediate(), y],
                             )
                         }
                         sym::ctlz_nonzero => {
                             let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.ctlz.i{}", width);
+                            let llvm_name = &format!("llvm.ctlz.i{width}");
                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
                         }
                         sym::cttz_nonzero => {
                             let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.cttz.i{}", width);
+                            let llvm_name = &format!("llvm.cttz.i{width}");
                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
                         }
                         sym::ctpop => self.call_intrinsic(
-                            &format!("llvm.ctpop.i{}", width),
+                            &format!("llvm.ctpop.i{width}"),
                             &[args[0].immediate()],
                         ),
                         sym::bswap => {
@@ -253,13 +252,13 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                                 args[0].immediate() // byte swap a u8/i8 is just a no-op
                             } else {
                                 self.call_intrinsic(
-                                    &format!("llvm.bswap.i{}", width),
+                                    &format!("llvm.bswap.i{width}"),
                                     &[args[0].immediate()],
                                 )
                             }
                         }
                         sym::bitreverse => self.call_intrinsic(
-                            &format!("llvm.bitreverse.i{}", width),
+                            &format!("llvm.bitreverse.i{width}"),
                             &[args[0].immediate()],
                         ),
                         sym::rotate_left | sym::rotate_right => {
@@ -317,18 +316,12 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     self.const_bool(true)
                 } else if use_integer_compare {
                     let integer_ty = self.type_ix(layout.size().bits());
-                    let ptr_ty = self.type_ptr_to(integer_ty);
-                    let a_ptr = self.bitcast(a, ptr_ty);
-                    let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
-                    let b_ptr = self.bitcast(b, ptr_ty);
-                    let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
+                    let a_val = self.load(integer_ty, a, layout.align().abi);
+                    let b_val = self.load(integer_ty, b, layout.align().abi);
                     self.icmp(IntPredicate::IntEQ, a_val, b_val)
                 } else {
-                    let i8p_ty = self.type_i8p();
-                    let a_ptr = self.bitcast(a, i8p_ty);
-                    let b_ptr = self.bitcast(b, i8p_ty);
                     let n = self.const_usize(layout.size().bytes());
-                    let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
+                    let cmp = self.call_intrinsic("memcmp", &[a, b, n]);
                     match self.cx.sess().target.arch.as_ref() {
                         "avr" | "msp430" => self.icmp(IntPredicate::IntEQ, cmp, self.const_i16(0)),
                         _ => self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)),
@@ -383,10 +376,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         };
 
         if !fn_abi.ret.is_ignore() {
-            if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
-                let ptr_llty = self.type_ptr_to(ty.llvm_type(self));
-                let ptr = self.pointercast(result.llval, ptr_llty);
-                self.store(llval, ptr, result.align);
+            if let PassMode::Cast(_, _) = &fn_abi.ret.mode {
+                self.store(llval, result.llval, result.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
                     .val
@@ -410,9 +401,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
     fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
         // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
         // optimization pass replaces calls to this intrinsic with code to test type membership.
-        let i8p_ty = self.type_i8p();
-        let bitcast = self.bitcast(pointer, i8p_ty);
-        self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
+        self.call_intrinsic("llvm.type.test", &[pointer, typeid])
     }
 
     fn type_checked_load(
@@ -444,7 +433,7 @@ fn try_intrinsic<'ll>(
     dest: &'ll Value,
 ) {
     if bx.sess().panic_strategy() == PanicStrategy::Abort {
-        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.call(try_func_ty, None, None, try_func, &[data], None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
@@ -544,8 +533,8 @@ fn codegen_msvc_try<'ll>(
         //
         // More information can be found in libstd's seh.rs implementation.
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let slot = bx.alloca(bx.type_i8p(), ptr_align);
-        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+        let slot = bx.alloca(bx.type_ptr(), ptr_align);
+        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
 
         bx.switch_to_block(normal);
@@ -568,10 +557,10 @@ fn codegen_msvc_try<'ll>(
         //
         // When modifying, make sure that the type_name string exactly matches
         // the one used in library/panic_unwind/src/seh.rs.
-        let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
+        let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_ptr());
         let type_name = bx.const_bytes(b"rust_panic\0");
         let type_info =
-            bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
+            bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
         let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
         unsafe {
             llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
@@ -588,15 +577,15 @@ fn codegen_msvc_try<'ll>(
         bx.switch_to_block(catchpad_rust);
         let flags = bx.const_i32(8);
         let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
-        let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
-        let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+        let ptr = bx.load(bx.type_ptr(), slot, ptr_align);
+        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
         bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
         bx.catch_ret(&funclet, caught);
 
         // The flag value of 64 indicates a "catch-all".
         bx.switch_to_block(catchpad_foreign);
         let flags = bx.const_i32(64);
-        let null = bx.const_null(bx.type_i8p());
+        let null = bx.const_null(bx.type_ptr());
         let funclet = bx.catch_pad(cs, &[null, flags, null]);
         bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet));
         bx.catch_ret(&funclet, caught);
@@ -655,7 +644,7 @@ fn codegen_wasm_try<'ll>(
         //      ret i32 1
         //   }
         //
-        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
 
         bx.switch_to_block(normal);
@@ -665,13 +654,13 @@ fn codegen_wasm_try<'ll>(
         let cs = bx.catch_switch(None, None, &[catchpad]);
 
         bx.switch_to_block(catchpad);
-        let null = bx.const_null(bx.type_i8p());
+        let null = bx.const_null(bx.type_ptr());
         let funclet = bx.catch_pad(cs, &[null]);
 
         let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[funclet.cleanuppad()]);
         let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]);
 
-        let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
         bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
         bx.catch_ret(&funclet, caught);
 
@@ -723,7 +712,7 @@ fn codegen_gnu_try<'ll>(
         let try_func = llvm::get_param(bx.llfn(), 0);
         let data = llvm::get_param(bx.llfn(), 1);
         let catch_func = llvm::get_param(bx.llfn(), 2);
-        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
 
         bx.switch_to_block(then);
@@ -736,12 +725,12 @@ fn codegen_gnu_try<'ll>(
         // the landing pad clauses the exception's type had been matched to.
         // rust_try ignores the selector.
         bx.switch_to_block(catch);
-        let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
+        let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false);
         let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
-        let tydesc = bx.const_null(bx.type_i8p());
+        let tydesc = bx.const_null(bx.type_ptr());
         bx.add_clause(vals, tydesc);
         let ptr = bx.extract_value(vals, 0);
-        let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
         bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
         bx.ret(bx.const_i32(1));
     });
@@ -787,7 +776,7 @@ fn codegen_emcc_try<'ll>(
         let try_func = llvm::get_param(bx.llfn(), 0);
         let data = llvm::get_param(bx.llfn(), 1);
         let catch_func = llvm::get_param(bx.llfn(), 2);
-        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
 
         bx.switch_to_block(then);
@@ -800,10 +789,10 @@ fn codegen_emcc_try<'ll>(
         // the landing pad clauses the exception's type had been matched to.
         bx.switch_to_block(catch);
         let tydesc = bx.eh_catch_typeinfo();
-        let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
+        let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false);
         let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2);
         bx.add_clause(vals, tydesc);
-        bx.add_clause(vals, bx.const_null(bx.type_i8p()));
+        bx.add_clause(vals, bx.const_null(bx.type_ptr()));
         let ptr = bx.extract_value(vals, 0);
         let selector = bx.extract_value(vals, 1);
 
@@ -816,7 +805,7 @@ fn codegen_emcc_try<'ll>(
         // create an alloca and pass a pointer to that.
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
         let i8_align = bx.tcx().data_layout.i8_align.abi;
-        let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
+        let catch_data_type = bx.type_struct(&[bx.type_ptr(), bx.type_bool()], false);
         let catch_data = bx.alloca(catch_data_type, ptr_align);
         let catch_data_0 =
             bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
@@ -824,9 +813,8 @@ fn codegen_emcc_try<'ll>(
         let catch_data_1 =
             bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
         bx.store(is_rust_panic, catch_data_1, i8_align);
-        let catch_data = bx.bitcast(catch_data, bx.type_i8p());
 
-        let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
         bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None);
         bx.ret(bx.const_i32(1));
     });
@@ -967,8 +955,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let place = PlaceRef::alloca(bx, args[0].layout);
                 args[0].val.store(bx, place);
                 let int_ty = bx.type_ix(expected_bytes * 8);
-                let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
-                bx.load(int_ty, ptr, Align::ONE)
+                bx.load(int_ty, place.llval, Align::ONE)
             }
             _ => return_error!(InvalidMonomorphization::InvalidBitmask {
                 span,
@@ -1217,7 +1204,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
                 bx.store(ze, ptr, Align::ONE);
                 let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
-                let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
                 return Ok(bx.load(array_ty, ptr, Align::ONE));
             }
             _ => return_error!(InvalidMonomorphization::CannotReturn {
@@ -1283,7 +1269,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
             _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
         };
-        let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
+        let llvm_name = &format!("llvm.{intr_name}.v{in_len}{elem_ty_str}");
         let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
         let c = bx.call(
             fn_ty,
@@ -1321,50 +1307,34 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     // FIXME: use:
     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182
     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81
-    fn llvm_vector_str(
-        elem_ty: Ty<'_>,
-        vec_len: u64,
-        no_pointers: usize,
-        bx: &Builder<'_, '_, '_>,
-    ) -> String {
-        let p0s: String = "p0".repeat(no_pointers);
+    fn llvm_vector_str(bx: &Builder<'_, '_, '_>, elem_ty: Ty<'_>, vec_len: u64) -> String {
         match *elem_ty.kind() {
             ty::Int(v) => format!(
-                "v{}{}i{}",
+                "v{}i{}",
                 vec_len,
-                p0s,
                 // Normalize to prevent crash if v: IntTy::Isize
                 v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
             ),
             ty::Uint(v) => format!(
-                "v{}{}i{}",
+                "v{}i{}",
                 vec_len,
-                p0s,
                 // Normalize to prevent crash if v: UIntTy::Usize
                 v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
             ),
-            ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()),
+            ty::Float(v) => format!("v{}f{}", vec_len, v.bit_width()),
+            ty::RawPtr(_) => format!("v{}p0", vec_len),
             _ => unreachable!(),
         }
     }
 
-    fn llvm_vector_ty<'ll>(
-        cx: &CodegenCx<'ll, '_>,
-        elem_ty: Ty<'_>,
-        vec_len: u64,
-        mut no_pointers: usize,
-    ) -> &'ll Type {
-        // FIXME: use cx.layout_of(ty).llvm_type() ?
-        let mut elem_ty = match *elem_ty.kind() {
+    fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type {
+        let elem_ty = match *elem_ty.kind() {
             ty::Int(v) => cx.type_int_from_ty(v),
             ty::Uint(v) => cx.type_uint_from_ty(v),
             ty::Float(v) => cx.type_float_from_ty(v),
+            ty::RawPtr(_) => cx.type_ptr(),
             _ => unreachable!(),
         };
-        while no_pointers > 0 {
-            elem_ty = cx.type_ptr_to(elem_ty);
-            no_pointers -= 1;
-        }
         cx.type_vector(elem_ty, vec_len)
     }
 
@@ -1419,47 +1389,26 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
         );
 
-        // This counts how many pointers
-        fn ptr_count(t: Ty<'_>) -> usize {
-            match t.kind() {
-                ty::RawPtr(p) => 1 + ptr_count(p.ty),
-                _ => 0,
-            }
-        }
-
-        // Non-ptr type
-        fn non_ptr(t: Ty<'_>) -> Ty<'_> {
-            match t.kind() {
-                ty::RawPtr(p) => non_ptr(p.ty),
-                _ => t,
-            }
-        }
-
         // The second argument must be a simd vector with an element type that's a pointer
         // to the element type of the first argument
         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
-        let (pointer_count, underlying_ty) = match element_ty1.kind() {
-            ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
-            _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ExpectedElementType {
-                        span,
-                        name,
-                        expected_element: element_ty1,
-                        second_arg: arg_tys[1],
-                        in_elem,
-                        in_ty,
-                        mutability: ExpectedPointerMutability::Not,
-                    }
-                );
-                unreachable!();
+
+        require!(
+            matches!(
+                element_ty1.kind(),
+                ty::RawPtr(p) if p.ty == in_elem && p.ty.kind() == element_ty0.kind()
+            ),
+            InvalidMonomorphization::ExpectedElementType {
+                span,
+                name,
+                expected_element: element_ty1,
+                second_arg: arg_tys[1],
+                in_elem,
+                in_ty,
+                mutability: ExpectedPointerMutability::Not,
             }
-        };
-        assert!(pointer_count > 0);
-        assert_eq!(pointer_count - 1, ptr_count(element_ty0));
-        assert_eq!(underlying_ty, non_ptr(element_ty0));
+        );
 
         // The element type of the third argument must be a signed integer type of any width:
         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
@@ -1490,15 +1439,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         };
 
         // Type of the vector of pointers:
-        let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
-        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
+        let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
+        let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len);
 
         // Type of the vector of elements:
-        let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
-        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
+        let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
+        let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len);
 
         let llvm_intrinsic =
-            format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
+            format!("llvm.masked.gather.{llvm_elem_vec_str}.{llvm_pointer_vec_str}");
         let fn_ty = bx.type_func(
             &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
             llvm_elem_vec_ty,
@@ -1559,50 +1508,28 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         );
 
-        // This counts how many pointers
-        fn ptr_count(t: Ty<'_>) -> usize {
-            match t.kind() {
-                ty::RawPtr(p) => 1 + ptr_count(p.ty),
-                _ => 0,
-            }
-        }
-
-        // Non-ptr type
-        fn non_ptr(t: Ty<'_>) -> Ty<'_> {
-            match t.kind() {
-                ty::RawPtr(p) => non_ptr(p.ty),
-                _ => t,
-            }
-        }
-
         // The second argument must be a simd vector with an element type that's a pointer
         // to the element type of the first argument
         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
-        let (pointer_count, underlying_ty) = match element_ty1.kind() {
-            ty::RawPtr(p) if p.ty == in_elem && p.mutbl.is_mut() => {
-                (ptr_count(element_ty1), non_ptr(element_ty1))
-            }
-            _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ExpectedElementType {
-                        span,
-                        name,
-                        expected_element: element_ty1,
-                        second_arg: arg_tys[1],
-                        in_elem,
-                        in_ty,
-                        mutability: ExpectedPointerMutability::Mut,
-                    }
-                );
-                unreachable!();
+
+        require!(
+            matches!(
+                element_ty1.kind(),
+                ty::RawPtr(p)
+                    if p.ty == in_elem && p.mutbl.is_mut() && p.ty.kind() == element_ty0.kind()
+            ),
+            InvalidMonomorphization::ExpectedElementType {
+                span,
+                name,
+                expected_element: element_ty1,
+                second_arg: arg_tys[1],
+                in_elem,
+                in_ty,
+                mutability: ExpectedPointerMutability::Mut,
             }
-        };
-        assert!(pointer_count > 0);
-        assert_eq!(pointer_count - 1, ptr_count(element_ty0));
-        assert_eq!(underlying_ty, non_ptr(element_ty0));
+        );
 
         // The element type of the third argument must be a signed integer type of any width:
         match element_ty2.kind() {
@@ -1634,15 +1561,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         let ret_t = bx.type_void();
 
         // Type of the vector of pointers:
-        let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
-        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
+        let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
+        let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len);
 
         // Type of the vector of elements:
-        let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
-        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
+        let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
+        let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len);
 
         let llvm_intrinsic =
-            format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
+            format!("llvm.masked.scatter.{llvm_elem_vec_str}.{llvm_pointer_vec_str}");
         let fn_ty =
             bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
         let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
@@ -1857,11 +1784,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         }
 
-        if in_elem == out_elem {
-            return Ok(args[0].immediate());
-        } else {
-            return Ok(bx.pointercast(args[0].immediate(), llret_ty));
-        }
+        return Ok(args[0].immediate());
     }
 
     if name == sym::simd_expose_addr {
@@ -2074,6 +1997,52 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         simd_neg: Int => neg, Float => fneg;
     }
 
+    // Unary integer intrinsics
+    if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_cttz) {
+        let vec_ty = bx.cx.type_vector(
+            match *in_elem.kind() {
+                ty::Int(i) => bx.cx.type_int_from_ty(i),
+                ty::Uint(i) => bx.cx.type_uint_from_ty(i),
+                _ => return_error!(InvalidMonomorphization::UnsupportedOperation {
+                    span,
+                    name,
+                    in_ty,
+                    in_elem
+                }),
+            },
+            in_len as u64,
+        );
+        let intrinsic_name = match name {
+            sym::simd_bswap => "bswap",
+            sym::simd_bitreverse => "bitreverse",
+            sym::simd_ctlz => "ctlz",
+            sym::simd_cttz => "cttz",
+            _ => unreachable!(),
+        };
+        let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
+        let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,);
+
+        return if name == sym::simd_bswap && int_size == 8 {
+            // byte swap is no-op for i8/u8
+            Ok(args[0].immediate())
+        } else if matches!(name, sym::simd_ctlz | sym::simd_cttz) {
+            let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
+            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+            Ok(bx.call(
+                fn_ty,
+                None,
+                None,
+                f,
+                &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)],
+                None,
+            ))
+        } else {
+            let fn_ty = bx.type_func(&[vec_ty], vec_ty);
+            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+            Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None))
+        };
+    }
+
     if name == sym::simd_arith_offset {
         // This also checks that the first operand is a ptr type.
         let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 5aab06febe4..d283299ac46 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -28,7 +28,7 @@ pub use llvm_util::target_features;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use rustc_codegen_ssa::back::write::{
-    CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
+    CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
 };
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
@@ -141,18 +141,6 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         back::write::target_machine_factory(sess, optlvl, target_features)
     }
 
-    fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
-    where
-        F: FnOnce() -> T,
-        F: Send + 'static,
-        T: Send + 'static,
-    {
-        std::thread::spawn(move || {
-            let _profiler = TimeTraceProfiler::new(time_trace);
-            f()
-        })
-    }
-
     fn spawn_named_thread<F, T>(
         time_trace: bool,
         name: String,
@@ -212,7 +200,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     }
     fn run_fat_lto(
         cgcx: &CodegenContext<Self>,
-        modules: Vec<FatLTOInput<Self>>,
+        modules: Vec<FatLtoInput<Self>>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
     ) -> Result<LtoModuleCodegen<Self>, FatalError> {
         back::lto::run_fat(cgcx, modules, cached_modules)
@@ -298,21 +286,21 @@ impl CodegenBackend for LlvmCodegenBackend {
                     "ropi-rwpi",
                     "default",
                 ] {
-                    writeln!(out, "    {}", name);
+                    writeln!(out, "    {name}");
                 }
                 writeln!(out);
             }
             PrintKind::CodeModels => {
                 writeln!(out, "Available code models:");
                 for name in &["tiny", "small", "kernel", "medium", "large"] {
-                    writeln!(out, "    {}", name);
+                    writeln!(out, "    {name}");
                 }
                 writeln!(out);
             }
             PrintKind::TlsModels => {
                 writeln!(out, "Available TLS models:");
                 for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
-                    writeln!(out, "    {}", name);
+                    writeln!(out, "    {name}");
                 }
                 writeln!(out);
             }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index 45de284d22a..06e846a2b45 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -9,7 +9,7 @@ use libc::c_uint;
 use super::{DiagnosticInfo, SMDiagnostic};
 use rustc_span::InnerSpan;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum OptimizationDiagnosticKind {
     OptimizationRemark,
     OptimizationMissed,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 5fe6407ac4f..7407cfa8c5b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1073,7 +1073,7 @@ extern "C" {
 
     // Operations on array, pointer, and vector types (sequence types)
     pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type;
-    pub fn LLVMPointerType(ElementType: &Type, AddressSpace: c_uint) -> &Type;
+    pub fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type;
     pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
 
     pub fn LLVMGetElementType(Ty: &Type) -> &Type;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 4f20fbf2045..a76c9c9b735 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -315,7 +315,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
 
 pub fn print_version() {
     let (major, minor, patch) = get_version();
-    println!("LLVM version: {}.{}.{}", major, minor, patch);
+    println!("LLVM version: {major}.{minor}.{patch}");
 }
 
 pub fn get_version() -> (u32, u32, u32) {
@@ -390,11 +390,11 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll
 
     writeln!(out, "Features supported by rustc for this target:");
     for (feature, desc) in &rustc_target_features {
-        writeln!(out, "    {1:0$} - {2}.", max_feature_len, feature, desc);
+        writeln!(out, "    {feature:max_feature_len$} - {desc}.");
     }
     writeln!(out, "\nCode-generation features supported by LLVM for this target:");
     for (feature, desc) in &llvm_target_features {
-        writeln!(out, "    {1:0$} - {2}.", max_feature_len, feature, desc);
+        writeln!(out, "    {feature:max_feature_len$} - {desc}.");
     }
     if llvm_target_features.is_empty() {
         writeln!(out, "    Target features listing is not supported by this LLVM version.");
@@ -507,8 +507,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
             .features
             .split(',')
             .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
-            // Drop +atomics-32 feature introduced in LLVM 15.
-            .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0))
             .map(String::from),
     );
 
@@ -575,7 +573,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                         match (enable_disable, feat) {
                             ('-' | '+', TargetFeatureFoldStrength::Both(f))
                             | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
-                                Some(format!("{}{}", enable_disable, f))
+                                Some(format!("{enable_disable}{f}"))
                             }
                             _ => None,
                         }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 7e672a8dc33..8db6195d931 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -112,12 +112,6 @@ impl<'ll> CodegenCx<'ll, '_> {
         }
     }
 
-    pub(crate) fn type_pointee_for_align(&self, align: Align) -> &'ll Type {
-        // FIXME(eddyb) We could find a better approximation if ity.align < align.
-        let ity = Integer::approximate_align(self, align);
-        self.type_from_integer(ity)
-    }
-
     /// Return a LLVM type that has at most the required alignment,
     /// and exactly the required size, as a best-effort padding array.
     pub(crate) fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type {
@@ -189,17 +183,12 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
     }
 
-    fn type_ptr_to(&self, ty: &'ll Type) -> &'ll Type {
-        assert_ne!(
-            self.type_kind(ty),
-            TypeKind::Function,
-            "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead or explicitly specify an address space if it makes sense"
-        );
-        ty.ptr_to(AddressSpace::DATA)
+    fn type_ptr(&self) -> &'ll Type {
+        self.type_ptr_ext(AddressSpace::DATA)
     }
 
-    fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type {
-        ty.ptr_to(address_space)
+    fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type {
+        unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) }
     }
 
     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
@@ -247,12 +236,8 @@ impl Type {
         unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) }
     }
 
-    pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
-        Type::i8_llcx(llcx).ptr_to(AddressSpace::DATA)
-    }
-
-    fn ptr_to(&self, address_space: AddressSpace) -> &Type {
-        unsafe { llvm::LLVMPointerType(self, address_space.0) }
+    pub fn ptr_llcx(llcx: &llvm::Context) -> &Type {
+        unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::DATA.0) }
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 2dbd467cc84..32e71c6a641 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -23,7 +23,7 @@ fn uncached_llvm_type<'a, 'tcx>(
     match layout.abi {
         Abi::Scalar(_) => bug!("handled elsewhere"),
         Abi::Vector { element, count } => {
-            let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO);
+            let element = layout.scalar_llvm_type_at(cx, element);
             return cx.type_vector(element, count);
         }
         Abi::ScalarPair(..) => {
@@ -179,12 +179,7 @@ pub trait LayoutLlvmExt<'tcx> {
     fn is_llvm_scalar_pair(&self) -> bool;
     fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
     fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
-    fn scalar_llvm_type_at<'a>(
-        &self,
-        cx: &CodegenCx<'a, 'tcx>,
-        scalar: Scalar,
-        offset: Size,
-    ) -> &'a Type;
+    fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type;
     fn scalar_pair_element_llvm_type<'a>(
         &self,
         cx: &CodegenCx<'a, 'tcx>,
@@ -230,16 +225,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
                 return llty;
             }
             let llty = match *self.ty.kind() {
-                ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx))
-                }
-                ty::Adt(def, _) if def.is_box() => {
-                    cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
-                }
+                ty::Ref(..) | ty::RawPtr(_) => cx.type_ptr(),
+                ty::Adt(def, _) if def.is_box() => cx.type_ptr(),
                 ty::FnPtr(sig) => {
                     cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
                 }
-                _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO),
+                _ => self.scalar_llvm_type_at(cx, scalar),
             };
             cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
             return llty;
@@ -300,25 +291,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
         self.llvm_type(cx)
     }
 
-    fn scalar_llvm_type_at<'a>(
-        &self,
-        cx: &CodegenCx<'a, 'tcx>,
-        scalar: Scalar,
-        offset: Size,
-    ) -> &'a Type {
+    fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type {
         match scalar.primitive() {
             Int(i, _) => cx.type_from_integer(i),
             F32 => cx.type_f32(),
             F64 => cx.type_f64(),
-            Pointer(address_space) => {
-                // If we know the alignment, pick something better than i8.
-                let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
-                    cx.type_pointee_for_align(pointee.align)
-                } else {
-                    cx.type_i8()
-                };
-                cx.type_ptr_to_ext(pointee, address_space)
-            }
+            Pointer(address_space) => cx.type_ptr_ext(address_space),
         }
     }
 
@@ -364,8 +342,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
             return cx.type_i1();
         }
 
-        let offset = if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.align(cx).abi) };
-        self.scalar_llvm_type_at(cx, scalar, offset)
+        self.scalar_llvm_type_at(cx, scalar)
     }
 
     fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64 {
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 8800caa71d6..172c66a7af1 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -5,7 +5,7 @@ use crate::value::Value;
 use rustc_codegen_ssa::mir::operand::OperandRef;
 use rustc_codegen_ssa::{
     common::IntPredicate,
-    traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods},
+    traits::{BaseTypeMethods, BuilderMethods, ConstMethods},
 };
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::Ty;
@@ -26,24 +26,18 @@ fn round_pointer_up_to_alignment<'ll>(
 fn emit_direct_ptr_va_arg<'ll, 'tcx>(
     bx: &mut Builder<'_, 'll, 'tcx>,
     list: OperandRef<'tcx, &'ll Value>,
-    llty: &'ll Type,
     size: Size,
     align: Align,
     slot_size: Align,
     allow_higher_align: bool,
 ) -> (&'ll Value, Align) {
-    let va_list_ty = bx.type_i8p();
-    let va_list_ptr_ty = bx.type_ptr_to(va_list_ty);
-    let va_list_addr = if list.layout.llvm_type(bx.cx) != va_list_ptr_ty {
-        bx.bitcast(list.immediate(), va_list_ptr_ty)
-    } else {
-        list.immediate()
-    };
+    let va_list_ty = bx.type_ptr();
+    let va_list_addr = list.immediate();
 
     let ptr = bx.load(va_list_ty, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
 
     let (addr, addr_align) = if allow_higher_align && align > slot_size {
-        (round_pointer_up_to_alignment(bx, ptr, align, bx.cx().type_i8p()), align)
+        (round_pointer_up_to_alignment(bx, ptr, align, bx.type_ptr()), align)
     } else {
         (ptr, slot_size)
     };
@@ -56,9 +50,9 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
     if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big {
         let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
         let adjusted = bx.inbounds_gep(bx.type_i8(), addr, &[adjusted_size]);
-        (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
+        (adjusted, addr_align)
     } else {
-        (bx.bitcast(addr, bx.cx().type_ptr_to(llty)), addr_align)
+        (addr, addr_align)
     }
 }
 
@@ -81,7 +75,7 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
         (layout.llvm_type(bx.cx), layout.size, layout.align)
     };
     let (addr, addr_align) =
-        emit_direct_ptr_va_arg(bx, list, llty, size, align.abi, slot_size, allow_higher_align);
+        emit_direct_ptr_va_arg(bx, list, size, align.abi, slot_size, allow_higher_align);
     if indirect {
         let tmp_ret = bx.load(llty, addr, addr_align);
         bx.load(bx.cx.layout_of(target_ty).llvm_type(bx.cx), tmp_ret, align.abi)
@@ -146,7 +140,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
     bx.cond_br(use_stack, on_stack, in_reg);
 
     bx.switch_to_block(in_reg);
-    let top_type = bx.type_i8p();
+    let top_type = bx.type_ptr();
     let top = bx.struct_gep(va_list_ty, va_list_addr, reg_top_index);
     let top = bx.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
 
@@ -158,7 +152,6 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
         reg_addr = bx.gep(bx.type_i8(), reg_addr, &[offset]);
     }
     let reg_type = layout.llvm_type(bx);
-    let reg_addr = bx.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
     let reg_value = bx.load(reg_type, reg_addr, layout.align.abi);
     bx.br(end);
 
@@ -218,7 +211,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
     // Work out the address of the value in the register save area.
     let reg_ptr =
         bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
-    let reg_ptr_v = bx.load(bx.type_i8p(), reg_ptr, bx.tcx().data_layout.pointer_align.abi);
+    let reg_ptr_v = bx.load(bx.type_ptr(), reg_ptr, bx.tcx().data_layout.pointer_align.abi);
     let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8));
     let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding));
     let reg_addr = bx.gep(bx.type_i8(), reg_ptr_v, &[reg_off]);
@@ -234,7 +227,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
     // Work out the address of the value in the argument overflow area.
     let arg_ptr =
         bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 2));
-    let arg_ptr_v = bx.load(bx.type_i8p(), arg_ptr, bx.tcx().data_layout.pointer_align.abi);
+    let arg_ptr_v = bx.load(bx.type_ptr(), arg_ptr, bx.tcx().data_layout.pointer_align.abi);
     let arg_off = bx.const_u64(padding);
     let mem_addr = bx.gep(bx.type_i8(), arg_ptr_v, &[arg_off]);
 
@@ -246,14 +239,12 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
 
     // Return the appropriate result.
     bx.switch_to_block(end);
-    let val_addr = bx.phi(bx.type_i8p(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
+    let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
     let val_type = layout.llvm_type(bx);
     let val_addr = if indirect {
-        let ptr_type = bx.cx.type_ptr_to(val_type);
-        let ptr_addr = bx.bitcast(val_addr, bx.cx.type_ptr_to(ptr_type));
-        bx.load(ptr_type, ptr_addr, bx.tcx().data_layout.pointer_align.abi)
+        bx.load(bx.cx.type_ptr(), val_addr, bx.tcx().data_layout.pointer_align.abi)
     } else {
-        bx.bitcast(val_addr, bx.cx.type_ptr_to(val_type))
+        val_addr
     };
     bx.load(val_type, val_addr, layout.align.abi)
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index eefa4ac34dd..cd6201648ee 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -748,7 +748,7 @@ fn link_natively<'a>(
 
     for print in &sess.opts.prints {
         if print.kind == PrintKind::LinkArgs {
-            let content = format!("{:?}", cmd);
+            let content = format!("{cmd:?}");
             print.out.overwrite(&content, sess);
         }
     }
@@ -1236,22 +1236,21 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
         }
     }
 
-    let channel = option_env!("CFG_RELEASE_CHANNEL")
-        .map(|channel| format!("-{}", channel))
-        .unwrap_or_default();
+    let channel =
+        option_env!("CFG_RELEASE_CHANNEL").map(|channel| format!("-{channel}")).unwrap_or_default();
 
     if sess.target.is_like_osx {
         // On Apple platforms, the sanitizer is always built as a dylib, and
         // LLVM will link to `@rpath/*.dylib`, so we need to specify an
         // rpath to the library as well (the rpath should be absolute, see
         // PR #41352 for details).
-        let filename = format!("rustc{}_rt.{}", channel, name);
+        let filename = format!("rustc{channel}_rt.{name}");
         let path = find_sanitizer_runtime(&sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
         linker.link_dylib(&filename, false, true);
     } else {
-        let filename = format!("librustc{}_rt.{}.a", channel, name);
+        let filename = format!("librustc{channel}_rt.{name}.a");
         let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
         linker.link_whole_rlib(&path);
     }
@@ -1415,12 +1414,12 @@ fn print_native_static_libs(
                     } else if sess.target.linker_flavor.is_gnu() {
                         Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
                     } else {
-                        Some(format!("-l{}", name))
+                        Some(format!("-l{name}"))
                     }
                 }
                 NativeLibKind::Framework { .. } => {
                     // ld-only syntax, since there are no frameworks in MSVC
-                    Some(format!("-framework {}", name))
+                    Some(format!("-framework {name}"))
                 }
                 // These are included, no need to print them
                 NativeLibKind::Static { bundle: None | Some(true), .. }
@@ -1457,12 +1456,12 @@ fn print_native_static_libs(
             // `foo.lib` file if the dll doesn't actually export any symbols, so we
             // check to see if the file is there and just omit linking to it if it's
             // not present.
-            let name = format!("{}.dll.lib", lib);
+            let name = format!("{lib}.dll.lib");
             if path.join(&name).exists() {
                 lib_args.push(name);
             }
         } else {
-            lib_args.push(format!("-l{}", lib));
+            lib_args.push(format!("-l{lib}"));
         }
     }
 
@@ -1628,8 +1627,8 @@ fn exec_linker(
                 write!(f, "\"")?;
                 for c in self.arg.chars() {
                     match c {
-                        '"' => write!(f, "\\{}", c)?,
-                        c => write!(f, "{}", c)?,
+                        '"' => write!(f, "\\{c}")?,
+                        c => write!(f, "{c}")?,
                     }
                 }
                 write!(f, "\"")?;
@@ -1646,8 +1645,8 @@ fn exec_linker(
                 // ensure the line is interpreted as one whole argument.
                 for c in self.arg.chars() {
                     match c {
-                        '\\' | ' ' => write!(f, "\\{}", c)?,
-                        c => write!(f, "{}", c)?,
+                        '\\' | ' ' => write!(f, "\\{c}")?,
+                        c => write!(f, "{c}")?,
                     }
                 }
             }
@@ -2284,7 +2283,7 @@ fn add_order_independent_options(
         } else {
             ""
         };
-        cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
+        cmd.arg(format!("--dynamic-linker={prefix}ld.so.1"));
     }
 
     if sess.target.eh_frame_header {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index cd56f85cccd..4c04fc60b98 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -309,7 +309,7 @@ impl<'a> GccLinker<'a> {
             self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
         };
         self.linker_args(&[
-            &format!("-plugin-opt={}", opt_level),
+            &format!("-plugin-opt={opt_level}"),
             &format!("-plugin-opt=mcpu={}", self.target_cpu),
         ]);
     }
@@ -487,7 +487,7 @@ impl<'a> Linker for GccLinker<'a> {
 
     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{lib}"));
     }
 
     fn link_framework(&mut self, framework: &str, as_needed: bool) {
@@ -671,8 +671,8 @@ impl<'a> Linker for GccLinker<'a> {
             let res: io::Result<()> = try {
                 let mut f = BufWriter::new(File::create(&path)?);
                 for sym in symbols {
-                    debug!("  _{}", sym);
-                    writeln!(f, "_{}", sym)?;
+                    debug!("  _{sym}");
+                    writeln!(f, "_{sym}")?;
                 }
             };
             if let Err(error) = res {
@@ -686,8 +686,8 @@ impl<'a> Linker for GccLinker<'a> {
                 // because LD doesn't like when it's empty
                 writeln!(f, "EXPORTS")?;
                 for symbol in symbols {
-                    debug!("  _{}", symbol);
-                    writeln!(f, "  {}", symbol)?;
+                    debug!("  _{symbol}");
+                    writeln!(f, "  {symbol}")?;
                 }
             };
             if let Err(error) = res {
@@ -701,8 +701,8 @@ impl<'a> Linker for GccLinker<'a> {
                 if !symbols.is_empty() {
                     writeln!(f, "  global:")?;
                     for sym in symbols {
-                        debug!("    {};", sym);
-                        writeln!(f, "    {};", sym)?;
+                        debug!("    {sym};");
+                        writeln!(f, "    {sym};")?;
                     }
                 }
                 writeln!(f, "\n  local:\n    *;\n}};")?;
@@ -837,7 +837,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         // `foo.lib` file if the dll doesn't actually export any symbols, so we
         // check to see if the file is there and just omit linking to it if it's
         // not present.
-        let name = format!("{}.dll.lib", lib);
+        let name = format!("{lib}.dll.lib");
         if path.join(&name).exists() {
             self.cmd.arg(name);
         }
@@ -977,8 +977,8 @@ impl<'a> Linker for MsvcLinker<'a> {
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
             for symbol in symbols {
-                debug!("  _{}", symbol);
-                writeln!(f, "  {}", symbol)?;
+                debug!("  _{symbol}");
+                writeln!(f, "  {symbol}")?;
             }
         };
         if let Err(error) = res {
@@ -992,7 +992,7 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn subsystem(&mut self, subsystem: &str) {
         // Note that previous passes of the compiler validated this subsystem,
         // so we just blindly pass it to the linker.
-        self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
+        self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}"));
 
         // Windows has two subsystems we're interested in right now, the console
         // and windows subsystems. These both implicitly have different entry
@@ -1147,7 +1147,7 @@ impl<'a> Linker for EmLinker<'a> {
             &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
         )
         .unwrap();
-        debug!("{}", encoded);
+        debug!("{encoded}");
 
         arg.push(encoded);
 
@@ -1350,7 +1350,7 @@ impl<'a> Linker for L4Bender<'a> {
     }
     fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
         self.hint_static();
-        self.cmd.arg(format!("-PC{}", lib));
+        self.cmd.arg(format!("-PC{lib}"));
     }
     fn link_rlib(&mut self, lib: &Path) {
         self.hint_static();
@@ -1399,7 +1399,7 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
         self.hint_static();
-        self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
+        self.cmd.arg("--whole-archive").arg(format!("-l{lib}"));
         self.cmd.arg("--no-whole-archive");
     }
 
@@ -1453,7 +1453,7 @@ impl<'a> Linker for L4Bender<'a> {
     }
 
     fn subsystem(&mut self, subsystem: &str) {
-        self.cmd.arg(&format!("--subsystem {}", subsystem));
+        self.cmd.arg(&format!("--subsystem {subsystem}"));
     }
 
     fn reset_per_library_state(&mut self) {
@@ -1518,12 +1518,12 @@ impl<'a> AixLinker<'a> {
 impl<'a> Linker for AixLinker<'a> {
     fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{lib}"));
     }
 
     fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
         self.hint_static();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{lib}"));
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -1573,7 +1573,7 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{lib}"));
     }
 
     fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
@@ -1626,12 +1626,12 @@ impl<'a> Linker for AixLinker<'a> {
             let mut f = BufWriter::new(File::create(&path)?);
             // FIXME: use llvm-nm to generate export list.
             for symbol in symbols {
-                debug!("  _{}", symbol);
-                writeln!(f, "  {}", symbol)?;
+                debug!("  _{symbol}");
+                writeln!(f, "  {symbol}")?;
             }
         };
         if let Err(e) = res {
-            self.sess.fatal(format!("failed to write export file: {}", e));
+            self.sess.fatal(format!("failed to write export file: {e}"));
         }
         self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
     }
@@ -1908,7 +1908,7 @@ impl<'a> Linker for BpfLinker<'a> {
         let res: io::Result<()> = try {
             let mut f = BufWriter::new(File::create(&path)?);
             for sym in symbols {
-                writeln!(f, "{}", sym)?;
+                writeln!(f, "{sym}")?;
             }
         };
         if let Err(error) = res {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index c4bb51edade..5c7df29444b 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -158,20 +158,19 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a
     {
         let offset = metadata_symbol.address() as usize;
         if offset < 4 {
-            return Err(format!("Invalid metadata symbol offset: {}", offset));
+            return Err(format!("Invalid metadata symbol offset: {offset}"));
         }
         // The offset specifies the location of rustc metadata in the comment section.
         // The metadata is preceded by a 4-byte length field.
         let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize;
         if offset + len > (info_data.len() as usize) {
             return Err(format!(
-                "Metadata at offset {} with size {} is beyond .info section",
-                offset, len
+                "Metadata at offset {offset} with size {len} is beyond .info section"
             ));
         }
         return Ok(&info_data[offset..(offset + len)]);
     } else {
-        return Err(format!("Unable to find symbol {}", AIX_METADATA_SYMBOL_NAME));
+        return Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}"));
     };
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 0b5656c9ad1..18268622341 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -86,7 +86,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
     output.pop(); // strip filename
     let output = fs::canonicalize(&output).unwrap_or(output);
     let relative = path_relative_from(&lib, &output)
-        .unwrap_or_else(|| panic!("couldn't create relative path from {:?} to {:?}", output, lib));
+        .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
     // FIXME (#9639): This needs to handle non-utf8 paths
     format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 0bbb6c9c338..40718525741 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -349,8 +349,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     /// Directory into which should the LLVM optimization remarks be written.
     /// If `None`, they will be written to stderr.
     pub remark_dir: Option<PathBuf>,
-    /// Worker thread number
-    pub worker: usize,
     /// The incremental compilation session directory, or None if we are not
     /// compiling incrementally
     pub incr_comp_session_dir: Option<PathBuf>,
@@ -376,38 +374,39 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
 
 fn generate_lto_work<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
-    needs_fat_lto: Vec<FatLTOInput<B>>,
+    needs_fat_lto: Vec<FatLtoInput<B>>,
     needs_thin_lto: Vec<(String, B::ThinBuffer)>,
     import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
 ) -> Vec<(WorkItem<B>, u64)> {
     let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work");
 
-    let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() {
+    if !needs_fat_lto.is_empty() {
         assert!(needs_thin_lto.is_empty());
-        let lto_module =
+        let module =
             B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise());
-        (vec![lto_module], vec![])
+        // We are adding a single work item, so the cost doesn't matter.
+        vec![(WorkItem::LTO(module), 0)]
     } else {
         assert!(needs_fat_lto.is_empty());
-        B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise())
-    };
-
-    lto_modules
-        .into_iter()
-        .map(|module| {
-            let cost = module.cost();
-            (WorkItem::LTO(module), cost)
-        })
-        .chain(copy_jobs.into_iter().map(|wp| {
-            (
-                WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
-                    name: wp.cgu_name.clone(),
-                    source: wp,
-                }),
-                0,
-            )
-        }))
-        .collect()
+        let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
+            .unwrap_or_else(|e| e.raise());
+        lto_modules
+            .into_iter()
+            .map(|module| {
+                let cost = module.cost();
+                (WorkItem::LTO(module), cost)
+            })
+            .chain(copy_jobs.into_iter().map(|wp| {
+                (
+                    WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
+                        name: wp.cgu_name.clone(),
+                        source: wp,
+                    }),
+                    0, // copying is very cheap
+                )
+            }))
+            .collect()
+    }
 }
 
 pub struct CompiledModules {
@@ -709,7 +708,7 @@ impl<B: WriteBackendMethods> WorkItem<B> {
         fn desc(short: &str, _long: &str, name: &str) -> String {
             // The short label is three bytes, and is followed by a space. That
             // leaves 11 bytes for the CGU name. How we obtain those 11 bytes
-            // depends on the the CGU name form.
+            // depends on the CGU name form.
             //
             // - Non-incremental, e.g. `regex.f10ba03eb5ec7975-cgu.0`: the part
             //   before the `-cgu.0` is the same for every CGU, so use the
@@ -742,22 +741,32 @@ impl<B: WriteBackendMethods> WorkItem<B> {
         }
 
         match self {
-            WorkItem::Optimize(m) => desc("opt", "optimize module {}", &m.name),
-            WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for {}", &m.name),
-            WorkItem::LTO(m) => desc("lto", "LTO module {}", m.name()),
+            WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name),
+            WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name),
+            WorkItem::LTO(m) => desc("lto", "LTO module", m.name()),
         }
     }
 }
 
 /// A result produced by the backend.
 pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
-    Compiled(CompiledModule),
+    /// The backend has finished compiling a CGU, nothing more required.
+    Finished(CompiledModule),
+
+    /// The backend has finished compiling a CGU, which now needs linking
+    /// because `-Zcombine-cgu` was specified.
     NeedsLink(ModuleCodegen<B::Module>),
-    NeedsFatLTO(FatLTOInput<B>),
-    NeedsThinLTO(String, B::ThinBuffer),
+
+    /// The backend has finished compiling a CGU, which now needs to go through
+    /// fat LTO.
+    NeedsFatLto(FatLtoInput<B>),
+
+    /// The backend has finished compiling a CGU, which now needs to go through
+    /// thin LTO.
+    NeedsThinLto(String, B::ThinBuffer),
 }
 
-pub enum FatLTOInput<B: WriteBackendMethods> {
+pub enum FatLtoInput<B: WriteBackendMethods> {
     Serialized { name: String, buffer: B::ModuleBuffer },
     InMemory(ModuleCodegen<B::Module>),
 }
@@ -846,7 +855,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
                     panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                 });
             }
-            Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))
+            Ok(WorkItemResult::NeedsThinLto(name, thin_buffer))
         }
         ComputedLtoType::Fat => match bitcode {
             Some(path) => {
@@ -854,9 +863,9 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
                 fs::write(&path, buffer.data()).unwrap_or_else(|e| {
                     panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                 });
-                Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }))
+                Ok(WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { name, buffer }))
             }
-            None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))),
+            None => Ok(WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module))),
         },
     }
 }
@@ -906,7 +915,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
             load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file)
         });
 
-    WorkItemResult::Compiled(CompiledModule {
+    WorkItemResult::Finished(CompiledModule {
         name: module.name,
         kind: ModuleKind::Regular,
         object,
@@ -936,7 +945,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
         || module.kind == ModuleKind::Allocator
     {
         let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
-        Ok(WorkItemResult::Compiled(module))
+        Ok(WorkItemResult::Finished(module))
     } else {
         Ok(WorkItemResult::NeedsLink(module))
     }
@@ -987,10 +996,15 @@ struct Diagnostic {
 }
 
 #[derive(PartialEq, Clone, Copy, Debug)]
-enum MainThreadWorkerState {
+enum MainThreadState {
+    /// Doing nothing.
     Idle,
+
+    /// Doing codegen, i.e. MIR-to-LLVM-IR conversion.
     Codegenning,
-    LLVMing,
+
+    /// Idle, but lending the compiler process's Token to an LLVM thread so it can do useful work.
+    Lending,
 }
 
 fn start_executing_work<B: ExtraBackendMethods>(
@@ -1089,7 +1103,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         exported_symbols,
         remark: sess.opts.cg.remark.clone(),
         remark_dir,
-        worker: 0,
         incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
         cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
         coordinator_send,
@@ -1242,7 +1255,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     // Each LLVM module is automatically sent back to the coordinator for LTO if
     // necessary. There's already optimizations in place to avoid sending work
     // back to the coordinator if LTO isn't requested.
-    return B::spawn_thread(cgcx.time_trace, move || {
+    return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || {
         let mut worker_id_counter = 0;
         let mut free_worker_ids = Vec::new();
         let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1285,10 +1298,19 @@ fn start_executing_work<B: ExtraBackendMethods>(
         // the implicit Token the compiler process owns no matter what.
         let mut tokens = Vec::new();
 
-        let mut main_thread_worker_state = MainThreadWorkerState::Idle;
-        let mut running = 0;
+        let mut main_thread_state = MainThreadState::Idle;
+
+        // How many LLVM worker threads are running while holding a Token. This
+        // *excludes* any that the main thread is lending a Token to.
+        let mut running_with_own_token = 0;
+
+        // How many LLVM worker threads are running in total. This *includes*
+        // any that the main thread is lending a Token to.
+        let running_with_any_token = |main_thread_state, running_with_own_token| {
+            running_with_own_token
+                + if main_thread_state == MainThreadState::Lending { 1 } else { 0 }
+        };
 
-        let prof = &cgcx.prof;
         let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
 
         // Run the message loop while there's still anything that needs message
@@ -1296,66 +1318,62 @@ fn start_executing_work<B: ExtraBackendMethods>(
         // wait for all existing work to finish, so many of the conditions here
         // only apply if codegen hasn't been aborted as they represent pending
         // work to be done.
-        while codegen_state == Ongoing
-            || running > 0
-            || main_thread_worker_state == MainThreadWorkerState::LLVMing
-            || (codegen_state == Completed
-                && !(work_items.is_empty()
-                    && needs_fat_lto.is_empty()
-                    && needs_thin_lto.is_empty()
-                    && lto_import_only_modules.is_empty()
-                    && main_thread_worker_state == MainThreadWorkerState::Idle))
-        {
+        loop {
             // While there are still CGUs to be codegened, the coordinator has
             // to decide how to utilize the compiler processes implicit Token:
             // For codegenning more CGU or for running them through LLVM.
             if codegen_state == Ongoing {
-                if main_thread_worker_state == MainThreadWorkerState::Idle {
+                if main_thread_state == MainThreadState::Idle {
                     // Compute the number of workers that will be running once we've taken as many
                     // items from the work queue as we can, plus one for the main thread. It's not
-                    // critically important that we use this instead of just `running`, but it
-                    // prevents the `queue_full_enough` heuristic from fluctuating just because a
-                    // worker finished up and we decreased the `running` count, even though we're
-                    // just going to increase it right after this when we put a new worker to work.
-                    let extra_tokens = tokens.len().checked_sub(running).unwrap();
+                    // critically important that we use this instead of just
+                    // `running_with_own_token`, but it prevents the `queue_full_enough` heuristic
+                    // from fluctuating just because a worker finished up and we decreased the
+                    // `running_with_own_token` count, even though we're just going to increase it
+                    // right after this when we put a new worker to work.
+                    let extra_tokens = tokens.len().checked_sub(running_with_own_token).unwrap();
                     let additional_running = std::cmp::min(extra_tokens, work_items.len());
-                    let anticipated_running = running + additional_running + 1;
+                    let anticipated_running = running_with_own_token + additional_running + 1;
 
                     if !queue_full_enough(work_items.len(), anticipated_running) {
                         // The queue is not full enough, process more codegen units:
                         if codegen_worker_send.send(CguMessage).is_err() {
                             panic!("Could not send CguMessage to main thread")
                         }
-                        main_thread_worker_state = MainThreadWorkerState::Codegenning;
+                        main_thread_state = MainThreadState::Codegenning;
                     } else {
                         // The queue is full enough to not let the worker
                         // threads starve. Use the implicit Token to do some
                         // LLVM work too.
                         let (item, _) =
                             work_items.pop().expect("queue empty - queue_full_enough() broken?");
-                        let cgcx = CodegenContext {
-                            worker: get_worker_id(&mut free_worker_ids),
-                            ..cgcx.clone()
-                        };
-                        maybe_start_llvm_timer(
-                            prof,
-                            cgcx.config(item.module_kind()),
+                        main_thread_state = MainThreadState::Lending;
+                        spawn_work(
+                            &cgcx,
                             &mut llvm_start_time,
+                            get_worker_id(&mut free_worker_ids),
+                            item,
                         );
-                        main_thread_worker_state = MainThreadWorkerState::LLVMing;
-                        spawn_work(cgcx, item);
                     }
                 }
             } else if codegen_state == Completed {
-                // If we've finished everything related to normal codegen
-                // then it must be the case that we've got some LTO work to do.
-                // Perform the serial work here of figuring out what we're
-                // going to LTO and then push a bunch of work items onto our
-                // queue to do LTO
-                if work_items.is_empty()
-                    && running == 0
-                    && main_thread_worker_state == MainThreadWorkerState::Idle
+                if running_with_any_token(main_thread_state, running_with_own_token) == 0
+                    && work_items.is_empty()
                 {
+                    // All codegen work is done. Do we have LTO work to do?
+                    if needs_fat_lto.is_empty()
+                        && needs_thin_lto.is_empty()
+                        && lto_import_only_modules.is_empty()
+                    {
+                        // Nothing more to do!
+                        break;
+                    }
+
+                    // We have LTO work to do. Perform the serial work here of
+                    // figuring out what we're going to LTO and then push a
+                    // bunch of work items onto our queue to do LTO. This all
+                    // happens on the coordinator thread but it's very quick so
+                    // we don't worry about tokens.
                     assert!(!started_lto);
                     started_lto = true;
 
@@ -1379,20 +1397,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
                 // In this branch, we know that everything has been codegened,
                 // so it's just a matter of determining whether the implicit
                 // Token is free to use for LLVM work.
-                match main_thread_worker_state {
-                    MainThreadWorkerState::Idle => {
+                match main_thread_state {
+                    MainThreadState::Idle => {
                         if let Some((item, _)) = work_items.pop() {
-                            let cgcx = CodegenContext {
-                                worker: get_worker_id(&mut free_worker_ids),
-                                ..cgcx.clone()
-                            };
-                            maybe_start_llvm_timer(
-                                prof,
-                                cgcx.config(item.module_kind()),
+                            main_thread_state = MainThreadState::Lending;
+                            spawn_work(
+                                &cgcx,
                                 &mut llvm_start_time,
+                                get_worker_id(&mut free_worker_ids),
+                                item,
                             );
-                            main_thread_worker_state = MainThreadWorkerState::LLVMing;
-                            spawn_work(cgcx, item);
                         } else {
                             // There is no unstarted work, so let the main thread
                             // take over for a running worker. Otherwise the
@@ -1400,16 +1414,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
                             // We reduce the `running` counter by one. The
                             // `tokens.truncate()` below will take care of
                             // giving the Token back.
-                            debug_assert!(running > 0);
-                            running -= 1;
-                            main_thread_worker_state = MainThreadWorkerState::LLVMing;
+                            debug_assert!(running_with_own_token > 0);
+                            running_with_own_token -= 1;
+                            main_thread_state = MainThreadState::Lending;
                         }
                     }
-                    MainThreadWorkerState::Codegenning => bug!(
+                    MainThreadState::Codegenning => bug!(
                         "codegen worker should not be codegenning after \
                               codegen was already completed"
                     ),
-                    MainThreadWorkerState::LLVMing => {
+                    MainThreadState::Lending => {
                         // Already making good use of that token
                     }
                 }
@@ -1417,35 +1431,39 @@ fn start_executing_work<B: ExtraBackendMethods>(
                 // Don't queue up any more work if codegen was aborted, we're
                 // just waiting for our existing children to finish.
                 assert!(codegen_state == Aborted);
+                if running_with_any_token(main_thread_state, running_with_own_token) == 0 {
+                    break;
+                }
             }
 
             // Spin up what work we can, only doing this while we've got available
             // parallelism slots and work left to spawn.
-            while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() {
-                let (item, _) = work_items.pop().unwrap();
-
-                maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
-
-                let cgcx =
-                    CodegenContext { worker: get_worker_id(&mut free_worker_ids), ..cgcx.clone() };
-
-                spawn_work(cgcx, item);
-                running += 1;
+            if codegen_state != Aborted {
+                while !work_items.is_empty() && running_with_own_token < tokens.len() {
+                    let (item, _) = work_items.pop().unwrap();
+                    spawn_work(
+                        &cgcx,
+                        &mut llvm_start_time,
+                        get_worker_id(&mut free_worker_ids),
+                        item,
+                    );
+                    running_with_own_token += 1;
+                }
             }
 
-            // Relinquish accidentally acquired extra tokens
-            tokens.truncate(running);
+            // Relinquish accidentally acquired extra tokens.
+            tokens.truncate(running_with_own_token);
 
             // If a thread exits successfully then we drop a token associated
-            // with that worker and update our `running` count. We may later
-            // re-acquire a token to continue running more work. We may also not
-            // actually drop a token here if the worker was running with an
-            // "ephemeral token"
+            // with that worker and update our `running_with_own_token` count.
+            // We may later re-acquire a token to continue running more work.
+            // We may also not actually drop a token here if the worker was
+            // running with an "ephemeral token".
             let mut free_worker = |worker_id| {
-                if main_thread_worker_state == MainThreadWorkerState::LLVMing {
-                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                if main_thread_state == MainThreadState::Lending {
+                    main_thread_state = MainThreadState::Idle;
                 } else {
-                    running -= 1;
+                    running_with_own_token -= 1;
                 }
 
                 free_worker_ids.push(worker_id);
@@ -1461,17 +1479,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
                         Ok(token) => {
                             tokens.push(token);
 
-                            if main_thread_worker_state == MainThreadWorkerState::LLVMing {
+                            if main_thread_state == MainThreadState::Lending {
                                 // If the main thread token is used for LLVM work
                                 // at the moment, we turn that thread into a regular
                                 // LLVM worker thread, so the main thread is free
                                 // to react to codegen demand.
-                                main_thread_worker_state = MainThreadWorkerState::Idle;
-                                running += 1;
+                                main_thread_state = MainThreadState::Idle;
+                                running_with_own_token += 1;
                             }
                         }
                         Err(e) => {
-                            let msg = &format!("failed to acquire jobserver token: {}", e);
+                            let msg = &format!("failed to acquire jobserver token: {e}");
                             shared_emitter.fatal(msg);
                             codegen_state = Aborted;
                         }
@@ -1496,16 +1514,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     if !cgcx.opts.unstable_opts.no_parallel_llvm {
                         helper.request_token();
                     }
-                    assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
-                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                    assert_eq!(main_thread_state, MainThreadState::Codegenning);
+                    main_thread_state = MainThreadState::Idle;
                 }
 
                 Message::CodegenComplete => {
                     if codegen_state != Aborted {
                         codegen_state = Completed;
                     }
-                    assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
-                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                    assert_eq!(main_thread_state, MainThreadState::Codegenning);
+                    main_thread_state = MainThreadState::Idle;
                 }
 
                 // If codegen is aborted that means translation was aborted due
@@ -1513,7 +1531,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
                 // to exit as soon as possible, but we want to make sure all
                 // existing work has finished. Flag codegen as being done, and
                 // then conditions above will ensure no more work is spawned but
-                // we'll keep executing this loop until `running` hits 0.
+                // we'll keep executing this loop until `running_with_own_token`
+                // hits 0.
                 Message::CodegenAborted => {
                     codegen_state = Aborted;
                 }
@@ -1522,9 +1541,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     free_worker(worker_id);
 
                     match result {
-                        Ok(WorkItemResult::Compiled(compiled_module)) => {
+                        Ok(WorkItemResult::Finished(compiled_module)) => {
                             match compiled_module.kind {
                                 ModuleKind::Regular => {
+                                    assert!(needs_link.is_empty());
                                     compiled_modules.push(compiled_module);
                                 }
                                 ModuleKind::Allocator => {
@@ -1535,14 +1555,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
                             }
                         }
                         Ok(WorkItemResult::NeedsLink(module)) => {
+                            assert!(compiled_modules.is_empty());
                             needs_link.push(module);
                         }
-                        Ok(WorkItemResult::NeedsFatLTO(fat_lto_input)) => {
+                        Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
                             assert!(!started_lto);
+                            assert!(needs_thin_lto.is_empty());
                             needs_fat_lto.push(fat_lto_input);
                         }
-                        Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => {
+                        Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) => {
                             assert!(!started_lto);
+                            assert!(needs_fat_lto.is_empty());
                             needs_thin_lto.push((name, thin_buffer));
                         }
                         Err(Some(WorkerFatalError)) => {
@@ -1560,9 +1583,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
                 Message::AddImportOnlyModule { module_data, work_product } => {
                     assert!(!started_lto);
                     assert_eq!(codegen_state, Ongoing);
-                    assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
+                    assert_eq!(main_thread_state, MainThreadState::Codegenning);
                     lto_import_only_modules.push((module_data, work_product));
-                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                    main_thread_state = MainThreadState::Idle;
                 }
             }
         }
@@ -1595,7 +1618,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
             modules: compiled_modules,
             allocator_module: compiled_allocator_module,
         })
-    });
+    })
+    .expect("failed to spawn coordinator thread");
 
     // A heuristic that determines if we have enough LLVM WorkItems in the
     // queue so that the main thread can do LLVM work instead of codegen
@@ -1653,23 +1677,24 @@ fn start_executing_work<B: ExtraBackendMethods>(
         let quarter_of_workers = workers_running - 3 * workers_running / 4;
         items_in_queue > 0 && items_in_queue >= quarter_of_workers
     }
-
-    fn maybe_start_llvm_timer<'a>(
-        prof: &'a SelfProfilerRef,
-        config: &ModuleConfig,
-        llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
-    ) {
-        if config.time_module && llvm_start_time.is_none() {
-            *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes"));
-        }
-    }
 }
 
 /// `FatalError` is explicitly not `Send`.
 #[must_use]
 pub struct WorkerFatalError;
 
-fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
+fn spawn_work<'a, B: ExtraBackendMethods>(
+    cgcx: &'a CodegenContext<B>,
+    llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
+    worker_id: usize,
+    work: WorkItem<B>,
+) {
+    if cgcx.config(work.module_kind()).time_module && llvm_start_time.is_none() {
+        *llvm_start_time = Some(cgcx.prof.verbose_generic_activity("LLVM_passes"));
+    }
+
+    let cgcx = cgcx.clone();
+
     B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
         // Set up a destructor which will fire off a message that we're done as
         // we exit.
@@ -1692,11 +1717,8 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
             }
         }
 
-        let mut bomb = Bomb::<B> {
-            coordinator_send: cgcx.coordinator_send.clone(),
-            result: None,
-            worker_id: cgcx.worker,
-        };
+        let mut bomb =
+            Bomb::<B> { coordinator_send: cgcx.coordinator_send.clone(), result: None, worker_id };
 
         // Execute the work itself, and if it finishes successfully then flag
         // ourselves as a success as well.
@@ -1728,7 +1750,7 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
             })
         };
     })
-    .expect("failed to spawn thread");
+    .expect("failed to spawn work thread");
 }
 
 enum SharedEmitterMessage {
@@ -1962,19 +1984,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         )
     }
 
-    pub fn submit_pre_codegened_module_to_llvm(
-        &self,
-        tcx: TyCtxt<'_>,
-        module: ModuleCodegen<B::Module>,
-    ) {
-        self.wait_for_signal_to_codegen_item();
-        self.check_for_errors(tcx.sess);
-
-        // These are generally cheap and won't throw off scheduling.
-        let cost = 0;
-        submit_codegened_module_to_llvm(&self.backend, &self.coordinator.sender, module, cost);
-    }
-
     pub fn codegen_finished(&self, tcx: TyCtxt<'_>) {
         self.wait_for_signal_to_codegen_item();
         self.check_for_errors(tcx.sess);
@@ -2040,8 +2049,8 @@ pub fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
     })));
 }
 
-pub fn pre_lto_bitcode_filename(module_name: &str) -> String {
-    format!("{}.{}", module_name, PRE_LTO_BC_EXT)
+fn pre_lto_bitcode_filename(module_name: &str) -> String {
+    format!("{module_name}.{PRE_LTO_BC_EXT}")
 }
 
 fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 79c284ecfbf..4819ab22723 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -165,50 +165,27 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
 
             if let Some(entry_idx) = vptr_entry_idx {
-                let ptr_ty = cx.type_i8p();
+                let ptr_ty = cx.type_ptr();
                 let ptr_align = cx.tcx().data_layout.pointer_align.abi;
-                let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
-                let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
                 let gep = bx.inbounds_gep(
                     ptr_ty,
-                    llvtable,
+                    old_info,
                     &[bx.const_usize(u64::try_from(entry_idx).unwrap())],
                 );
                 let new_vptr = bx.load(ptr_ty, gep, ptr_align);
                 bx.nonnull_metadata(new_vptr);
                 // VTable loads are invariant.
                 bx.set_invariant_load(new_vptr);
-                bx.pointercast(new_vptr, vtable_ptr_ty)
+                new_vptr
             } else {
                 old_info
             }
         }
-        (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => {
-            let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
-            cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
-        }
+        (_, &ty::Dynamic(ref data, _, _)) => meth::get_vtable(cx, source, data.principal()),
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
 
-// Returns the vtable pointer type of a `dyn` or `dyn*` type
-fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
-    cx: &Cx,
-    target: Ty<'tcx>,
-    kind: ty::DynKind,
-) -> <Cx as BackendTypes>::Type {
-    cx.scalar_pair_element_backend_type(
-        cx.layout_of(match kind {
-            // vtable is the second field of `*mut dyn Trait`
-            ty::Dyn => Ty::new_mut_ptr(cx.tcx(), target),
-            // vtable is the second field of `dyn* Trait`
-            ty::DynStar => target,
-        }),
-        1,
-        true,
-    )
-}
-
 /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
 pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
@@ -222,8 +199,7 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
         | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
             assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
-            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
-            (bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, old_info))
+            (src, unsized_info(bx, a, b, old_info))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
@@ -248,11 +224,7 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 assert_eq!(result, None);
                 result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
             }
-            let (lldata, llextra) = result.unwrap();
-            let lldata_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true);
-            let llextra_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true);
-            // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-            (bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty))
+            result.unwrap()
         }
         _ => bug!("unsize_ptr: called on bad types"),
     }
@@ -271,11 +243,9 @@ pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
         "destination type must be a dyn*"
     );
-    // FIXME(dyn-star): We can remove this when all supported LLVMs use opaque ptrs only.
-    let unit_ptr = bx.cx().type_ptr_to(bx.cx().type_struct(&[], false));
     let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) {
-        TypeKind::Pointer => bx.pointercast(src, unit_ptr),
-        TypeKind::Integer => bx.inttoptr(src, unit_ptr),
+        TypeKind::Pointer => src,
+        TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()),
         // FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr.
         kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),
     };
@@ -398,11 +368,6 @@ pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     if flags == MemFlags::empty()
         && let Some(bty) = bx.cx().scalar_copy_backend_type(layout)
     {
-        // I look forward to only supporting opaque pointers
-        let pty = bx.type_ptr_to(bty);
-        let src = bx.pointercast(src, pty);
-        let dst = bx.pointercast(dst, pty);
-
         let temp = bx.load(bty, src, src_align);
         bx.store(temp, dst, dst_align);
     } else {
@@ -456,7 +421,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
         // depending on whether the target needs `argc` and `argv` to be passed in.
         let llfty = if cx.sess().target.main_needs_argc_argv {
-            cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
+            cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
         } else {
             cx.type_func(&[], cx.type_int())
         };
@@ -490,7 +455,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         bx.insert_reference_to_gdb_debug_scripts_section_global();
 
         let isize_ty = cx.type_isize();
-        let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
+        let ptr_ty = cx.type_ptr();
         let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
 
         let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type {
@@ -509,12 +474,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let i8_ty = cx.type_i8();
             let arg_sigpipe = bx.const_u8(sigpipe);
 
-            let start_ty =
-                cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty, i8_ty], isize_ty);
+            let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty);
             (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe])
         } else {
             debug!("using user-defined start fn");
-            let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
+            let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
             (rust_main, start_ty, vec![arg_argc, arg_argv])
         };
 
@@ -541,7 +505,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     } else {
         // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
         let arg_argc = bx.const_int(cx.type_int(), 0);
-        let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p()));
+        let arg_argv = bx.const_null(cx.type_ptr());
         (arg_argc, arg_argv)
     }
 }
@@ -664,9 +628,16 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
             )
         });
 
-        ongoing_codegen.submit_pre_codegened_module_to_llvm(
-            tcx,
+        ongoing_codegen.wait_for_signal_to_codegen_item();
+        ongoing_codegen.check_for_errors(tcx.sess);
+
+        // These modules are generally cheap and won't throw off scheduling.
+        let cost = 0;
+        submit_codegened_module_to_llvm(
+            &backend,
+            &ongoing_codegen.coordinator.sender,
             ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator },
+            cost,
         );
     }
 
@@ -761,7 +732,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                     module,
                     cost,
                 );
-                false
             }
             CguReuse::PreLto => {
                 submit_pre_lto_module_to_llvm(
@@ -773,7 +743,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                         source: cgu.previous_work_product(tcx),
                     },
                 );
-                true
             }
             CguReuse::PostLto => {
                 submit_post_lto_module_to_llvm(
@@ -784,9 +753,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                         source: cgu.previous_work_product(tcx),
                     },
                 );
-                true
             }
-        };
+        }
     }
 
     ongoing_codegen.codegen_finished(tcx);
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 64f799bb1e6..067c824aba0 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -414,7 +414,7 @@ fn push_debuginfo_type_name<'tcx>(
         }
         // Type parameters from polymorphized functions.
         ty::Param(_) => {
-            write!(output, "{:?}", t).unwrap();
+            write!(output, "{t:?}").unwrap();
         }
         ty::Error(_)
         | ty::Infer(_)
@@ -565,9 +565,9 @@ fn push_disambiguated_special_name(
     output: &mut String,
 ) {
     if cpp_like_debuginfo {
-        write!(output, "{}${}", label, disambiguator).unwrap();
+        write!(output, "{label}${disambiguator}").unwrap();
     } else {
-        write!(output, "{{{}#{}}}", label, disambiguator).unwrap();
+        write!(output, "{{{label}#{disambiguator}}}").unwrap();
     }
 }
 
@@ -651,15 +651,15 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
             ty::Int(ity) => {
                 let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
                 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
-                write!(output, "{}", val)
+                write!(output, "{val}")
             }
             ty::Uint(_) => {
                 let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
-                write!(output, "{}", val)
+                write!(output, "{val}")
             }
             ty::Bool => {
                 let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
-                write!(output, "{}", val)
+                write!(output, "{val}")
             }
             _ => {
                 // If we cannot evaluate the constant to a known type, we fall back
@@ -678,9 +678,9 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                 });
 
                 if cpp_like_debuginfo(tcx) {
-                    write!(output, "CONST${:x}", hash_short)
+                    write!(output, "CONST${hash_short:x}")
                 } else {
-                    write!(output, "{{CONST#{:x}}}", hash_short)
+                    write!(output, "{{CONST#{hash_short:x}}}")
                 }
             }
         },
@@ -752,7 +752,7 @@ fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
 }
 
 fn pop_close_angle_bracket(output: &mut String) {
-    assert!(output.ends_with('>'), "'output' does not end with '>': {}", output);
+    assert!(output.ends_with('>'), "'output' does not end with '>': {output}");
     output.pop();
     if output.ends_with(' ') {
         output.pop();
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index dbe1d6e8ba8..b7d8b9b45bf 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -177,31 +177,31 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
             }
             thorin::Error::NamelessSection(_, offset) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name);
-                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
                 diag =
                     handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
                 diag.set_arg("section", section);
-                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::MultipleRelocations(section, offset) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
                 diag.set_arg("section", section);
-                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::UnsupportedRelocation(section, offset) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
                 diag.set_arg("section", section);
-                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::MissingDwoName(id) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
-                diag.set_arg("id", format!("0x{:08x}", id));
+                diag.set_arg("id", format!("0x{id:08x}"));
                 diag
             }
             thorin::Error::NoCompilationUnits => {
@@ -251,7 +251,7 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
             }
             thorin::Error::StrAtOffset(_, offset) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
-                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::ParseIndex(_, section) => {
@@ -261,7 +261,7 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
             }
             thorin::Error::UnitNotInIndex(unit) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
-                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::RowNotInIndex(_, row) => {
@@ -275,7 +275,7 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
             }
             thorin::Error::EmptyUnit(unit) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit);
-                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::MultipleDebugInfoSection => {
@@ -292,12 +292,12 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
             }
             thorin::Error::DuplicateUnit(unit) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
-                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::MissingReferencedUnit(unit) => {
                 diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
-                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::NoOutputObjectCreated => {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 9abe7b25d0e..12146a54d3b 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -23,7 +23,6 @@ impl<'a, 'tcx> VirtualIndex {
         // Load the data pointer from the object.
         debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
         let llty = bx.fn_ptr_backend_type(fn_abi);
-        let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
 
         if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
             && bx.cx().sess().lto() == Lto::Fat
@@ -33,7 +32,7 @@ impl<'a, 'tcx> VirtualIndex {
                 .unwrap();
             let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
             let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
-            bx.pointercast(func, llty)
+            func
         } else {
             let ptr_align = bx.tcx().data_layout.pointer_align.abi;
             let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
@@ -54,7 +53,6 @@ impl<'a, 'tcx> VirtualIndex {
         debug!("get_int({:?}, {:?})", llvtable, self);
 
         let llty = bx.type_isize();
-        let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
         let usize_align = bx.tcx().data_layout.pointer_align.abi;
         let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
         let ptr = bx.load(llty, gep, usize_align);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index ed608bdbe9a..f13dfd96b8e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -439,8 +439,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
                 };
                 let ty = bx.cast_backend_type(cast_ty);
-                let addr = bx.pointercast(llslot, bx.type_ptr_to(ty));
-                bx.load(ty, addr, self.fn_abi.ret.layout.align.abi)
+                bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
             }
         };
         bx.ret(llval);
@@ -703,13 +702,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     with_no_trimmed_paths!({
                         if layout.abi.is_uninhabited() {
                             // Use this error even for the other intrinsics as it is more precise.
-                            format!("attempted to instantiate uninhabited type `{}`", ty)
+                            format!("attempted to instantiate uninhabited type `{ty}`")
                         } else if requirement == ValidityRequirement::Zero {
-                            format!("attempted to zero-initialize type `{}`, which is invalid", ty)
+                            format!("attempted to zero-initialize type `{ty}`, which is invalid")
                         } else {
                             format!(
-                                "attempted to leave type `{}` uninitialized, which is invalid",
-                                ty
+                                "attempted to leave type `{ty}` uninitialized, which is invalid"
                             )
                         }
                     })
@@ -853,9 +851,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             Some(intrinsic) => {
                 let dest = match ret_dest {
                     _ if fn_abi.ret.is_indirect() => llargs[0],
-                    ReturnDest::Nothing => {
-                        bx.const_undef(bx.type_ptr_to(bx.arg_memory_ty(&fn_abi.ret)))
-                    }
+                    ReturnDest::Nothing => bx.const_undef(bx.type_ptr()),
                     ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
                     ReturnDest::DirectOperand(_) => {
                         bug!("Cannot use direct operand with an intrinsic call")
@@ -1045,10 +1041,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             assert_eq!(
                 fn_abi.args.len(),
                 mir_args + 1,
-                "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}",
-                instance,
-                fn_span,
-                fn_abi,
+                "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}",
             );
             let location =
                 self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
@@ -1428,8 +1421,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // Have to load the argument, maybe while casting it.
             if let PassMode::Cast(ty, _) = &arg.mode {
                 let llty = bx.cast_backend_type(ty);
-                let addr = bx.pointercast(llval, bx.type_ptr_to(llty));
-                llval = bx.load(llty, addr, align.min(arg.layout.align.abi));
+                llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
             } else {
                 // We can't use `PlaceRef::load` here because the argument
                 // may have a type we don't treat as immediate, but the ABI
@@ -1555,7 +1547,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
         let llbb = self.llbb(bb);
         if base::wants_new_eh_instructions(self.cx.sess()) {
-            let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
+            let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{bb:?}"));
             let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
             let funclet = cleanup_bx.cleanup_pad(None, &[]);
             cleanup_bx.br(llbb);
@@ -1634,7 +1626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // represents that this is a catch-all block.
                 bx = Bx::build(self.cx, cp_llbb);
                 let null =
-                    bx.const_null(bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space));
+                    bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
                 let sixty_four = bx.const_i32(64);
                 funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
             } else {
@@ -1675,7 +1667,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         match self.cached_llbbs[bb] {
             CachedLlbb::None => {
                 // FIXME(eddyb) only name the block if `fewer_names` is `false`.
-                let llbb = Bx::append_block(self.cx, self.llfn, &format!("{:?}", bb));
+                let llbb = Bx::append_block(self.cx, self.llfn, &format!("{bb:?}"));
                 self.cached_llbbs[bb] = CachedLlbb::Some(llbb);
                 Some(llbb)
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 34b8d8b5a6f..4167a85ccd5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         } else {
             Some(match whole_local_var.or(fallback_var.clone()) {
                 Some(var) if var.name != kw::Empty => var.name.to_string(),
-                _ => format!("{:?}", local),
+                _ => format!("{local:?}"),
             })
         };
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 18201abd631..8821fb21fd0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -270,7 +270,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             sym::const_allocate => {
                 // returns a null pointer at runtime.
-                bx.const_null(bx.type_i8p())
+                bx.const_null(bx.type_ptr())
             }
 
             sym::const_deallocate => {
@@ -310,14 +310,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let ty = fn_args.type_at(0);
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let weak = instruction == "cxchgweak";
-                            let mut dst = args[0].immediate();
+                            let dst = args[0].immediate();
                             let mut cmp = args[1].immediate();
                             let mut src = args[2].immediate();
                             if ty.is_unsafe_ptr() {
                                 // Some platforms do not support atomic operations on pointers,
                                 // so we cast to integer first.
-                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
-                                dst = bx.pointercast(dst, ptr_llty);
                                 cmp = bx.ptrtoint(cmp, bx.type_isize());
                                 src = bx.ptrtoint(src, bx.type_isize());
                             }
@@ -342,13 +340,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let layout = bx.layout_of(ty);
                             let size = layout.size;
-                            let mut source = args[0].immediate();
+                            let source = args[0].immediate();
                             if ty.is_unsafe_ptr() {
                                 // Some platforms do not support atomic operations on pointers,
                                 // so we cast to integer first...
                                 let llty = bx.type_isize();
-                                let ptr_llty = bx.type_ptr_to(llty);
-                                source = bx.pointercast(source, ptr_llty);
                                 let result = bx.atomic_load(llty, source, parse_ordering(bx, ordering), size);
                                 // ... and then cast the result back to a pointer
                                 bx.inttoptr(result, bx.backend_type(layout))
@@ -365,12 +361,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let size = bx.layout_of(ty).size;
                             let mut val = args[1].immediate();
-                            let mut ptr = args[0].immediate();
+                            let ptr = args[0].immediate();
                             if ty.is_unsafe_ptr() {
                                 // Some platforms do not support atomic operations on pointers,
                                 // so we cast to integer first.
-                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
-                                ptr = bx.pointercast(ptr, ptr_llty);
                                 val = bx.ptrtoint(val, bx.type_isize());
                             }
                             bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size);
@@ -409,13 +403,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                         let ty = fn_args.type_at(0);
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
-                            let mut ptr = args[0].immediate();
+                            let ptr = args[0].immediate();
                             let mut val = args[1].immediate();
                             if ty.is_unsafe_ptr() {
                                 // Some platforms do not support atomic operations on pointers,
                                 // so we cast to integer first.
-                                let ptr_llty = bx.type_ptr_to(bx.type_isize());
-                                ptr = bx.pointercast(ptr, ptr_llty);
                                 val = bx.ptrtoint(val, bx.type_isize());
                             }
                             bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering))
@@ -470,10 +462,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         if !fn_abi.ret.is_ignore() {
-            if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
-                let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(ty));
-                let ptr = bx.pointercast(result.llval, ptr_llty);
-                bx.store(llval, ptr, result.align);
+            if let PassMode::Cast(..) = &fn_abi.ret.mode {
+                bx.store(llval, result.llval, result.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
                     .val
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 31c293d7c29..f90d1a0fc9c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -2,7 +2,6 @@ use super::place::PlaceRef;
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
-use crate::common::TypeKind;
 use crate::glue;
 use crate::traits::*;
 use crate::MemFlags;
@@ -132,7 +131,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
     ) -> Self {
         let alloc_align = alloc.inner().align;
         assert_eq!(alloc_align, layout.align.abi);
-        let ty = bx.type_ptr_to(bx.cx().backend_type(layout));
 
         let read_scalar = |start, size, s: abi::Scalar, ty| {
             let val = alloc
@@ -156,7 +154,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => {
                 let size = s.size(bx);
                 assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
-                let val = read_scalar(Size::ZERO, size, s, ty);
+                let val = read_scalar(Size::ZERO, size, s, bx.type_ptr());
                 OperandRef { val: OperandValue::Immediate(val), layout }
             }
             Abi::ScalarPair(
@@ -187,7 +185,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 let base_addr = bx.static_addr_of(init, alloc_align, None);
 
                 let llval = bx.const_ptr_byte_offset(base_addr, offset);
-                let llval = bx.const_bitcast(llval, ty);
                 bx.load_operand(PlaceRef::new_sized(llval, layout))
             }
         }
@@ -314,38 +311,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             ) => {
                 // Bools in union fields needs to be truncated.
                 *llval = bx.to_immediate(*llval, field);
-                // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-                let ty = bx.cx().immediate_backend_type(field);
-                if bx.type_kind(ty) == TypeKind::Pointer {
-                    *llval = bx.pointercast(*llval, ty);
-                }
             }
             (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
                 // Bools in union fields needs to be truncated.
                 *a = bx.to_immediate_scalar(*a, a_abi);
                 *b = bx.to_immediate_scalar(*b, b_abi);
-                // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-                let a_ty = bx.cx().scalar_pair_element_backend_type(field, 0, true);
-                let b_ty = bx.cx().scalar_pair_element_backend_type(field, 1, true);
-                if bx.type_kind(a_ty) == TypeKind::Pointer {
-                    *a = bx.pointercast(*a, a_ty);
-                }
-                if bx.type_kind(b_ty) == TypeKind::Pointer {
-                    *b = bx.pointercast(*b, b_ty);
-                }
             }
             // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
             (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
                 assert!(matches!(self.layout.abi, Abi::Vector { .. }));
 
-                let llty = bx.cx().backend_type(self.layout);
                 let llfield_ty = bx.cx().backend_type(field);
 
                 // Can't bitcast an aggregate, so round trip through memory.
-                let lltemp = bx.alloca(llfield_ty, field.align.abi);
-                let llptr = bx.pointercast(lltemp, bx.cx().type_ptr_to(llty));
+                let llptr = bx.alloca(llfield_ty, field.align.abi);
                 bx.store(*llval, llptr, field.align.abi);
-                *llval = bx.load(llfield_ty, lltemp, field.align.abi);
+                *llval = bx.load(llfield_ty, llptr, field.align.abi);
             }
             (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => {
                 bug!()
@@ -380,9 +361,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
             let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
             OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
         } else {
-            let bty = bx.cx().backend_type(layout);
-            let ptr_bty = bx.cx().type_ptr_to(bty);
-            OperandValue::Ref(bx.const_poison(ptr_bty), None, layout.align.abi)
+            let ptr = bx.cx().type_ptr();
+            OperandValue::Ref(bx.const_poison(ptr), None, layout.align.abi)
         }
     }
 
@@ -434,8 +414,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
                 if flags.contains(MemFlags::NONTEMPORAL) {
                     // HACK(nox): This is inefficient but there is no nontemporal memcpy.
                     let ty = bx.backend_type(dest.layout);
-                    let ptr = bx.pointercast(r, bx.type_ptr_to(ty));
-                    let val = bx.load(ty, ptr, source_align);
+                    let val = bx.load(ty, r, source_align);
                     bx.store_with_flags(val, dest.llval, dest.align, flags);
                     return;
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 90eab55f76e..64c6d17469b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -115,8 +115,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 }
                 Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
                     // ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer.
-                    let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
-                    bx.gep(bx.cx().type_i8(), byte_ptr, &[bx.const_usize(offset.bytes())])
+                    bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
                 }
                 Abi::Scalar(_) | Abi::ScalarPair(..) => {
                     // All fields of Scalar and ScalarPair layouts must have been handled by this point.
@@ -133,8 +132,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 }
             };
             PlaceRef {
-                // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types.
-                llval: bx.pointercast(llval, bx.cx().type_ptr_to(bx.cx().backend_type(field))),
+                llval,
                 llextra: if bx.cx().type_has_metadata(field.ty) { self.llextra } else { None },
                 layout: field,
                 align: effective_field_align,
@@ -194,20 +192,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
 
         debug!("struct_field_ptr: DST field offset: {:?}", offset);
 
-        // Cast and adjust pointer.
-        let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
-        let byte_ptr = bx.gep(bx.cx().type_i8(), byte_ptr, &[offset]);
+        // Adjust pointer.
+        let ptr = bx.gep(bx.cx().type_i8(), self.llval, &[offset]);
 
-        // Finally, cast back to the type expected.
-        let ll_fty = bx.cx().backend_type(field);
-        debug!("struct_field_ptr: Field type is {:?}", ll_fty);
-
-        PlaceRef {
-            llval: bx.pointercast(byte_ptr, bx.cx().type_ptr_to(ll_fty)),
-            llextra: self.llextra,
-            layout: field,
-            align: effective_field_align,
-        }
+        PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align }
     }
 
     /// Obtain the actual discriminant of a value.
@@ -416,11 +404,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     ) -> Self {
         let mut downcast = *self;
         downcast.layout = self.layout.for_variant(bx.cx(), variant_index);
-
-        // Cast to the appropriate variant struct type.
-        let variant_ty = bx.cx().backend_type(downcast.layout);
-        downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
-
         downcast
     }
 
@@ -431,11 +414,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     ) -> Self {
         let mut downcast = *self;
         downcast.layout = bx.cx().layout_of(ty);
-
-        // Cast to the appropriate type.
-        let variant_ty = bx.cx().backend_type(downcast.layout);
-        downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
-
         downcast
     }
 
@@ -515,13 +493,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         ));
                     }
 
-                    // Cast the place pointer type to the new
-                    // array or slice type (`*[%_; new_len]`).
-                    subslice.llval = bx.pointercast(
-                        subslice.llval,
-                        bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
-                    );
-
                     subslice
                 }
                 mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 1f90a28eb8e..07c61df2140 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -182,9 +182,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             OperandValue::Immediate(..) | OperandValue::Pair(..) => {
                 // When we have immediate(s), the alignment of the source is irrelevant,
                 // so we can store them using the destination's alignment.
-                let llty = bx.backend_type(src.layout);
-                let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
-                src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align));
+                src.val.store(bx, PlaceRef::new_sized_aligned(dst.llval, src.layout, dst.align));
             }
         }
     }
@@ -222,9 +220,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             OperandValue::Ref(ptr, meta, align) => {
                 debug_assert_eq!(meta, None);
                 debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
-                let cast_bty = bx.backend_type(cast);
-                let cast_ptr = bx.pointercast(ptr, bx.type_ptr_to(cast_bty));
-                let fake_place = PlaceRef::new_sized_aligned(cast_ptr, cast, align);
+                let fake_place = PlaceRef::new_sized_aligned(ptr, cast, align);
                 Some(bx.load_operand(fake_place).val)
             }
             OperandValue::ZeroSized => {
@@ -397,8 +393,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> OperandRef<'tcx, Bx::Value> {
         assert!(
             self.rvalue_creates_operand(rvalue, DUMMY_SP),
-            "cannot codegen {:?} to operand",
-            rvalue,
+            "cannot codegen {rvalue:?} to operand",
         );
 
         match *rvalue {
@@ -480,18 +475,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     {
                         if let OperandValue::Pair(data_ptr, meta) = operand.val {
                             if bx.cx().is_backend_scalar_pair(cast) {
-                                let data_cast = bx.pointercast(
-                                    data_ptr,
-                                    bx.cx().scalar_pair_element_backend_type(cast, 0, true),
-                                );
-                                OperandValue::Pair(data_cast, meta)
+                                OperandValue::Pair(data_ptr, meta)
                             } else {
-                                // cast to thin-ptr
-                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
-                                // pointer-cast of that pointer to desired pointer type.
-                                let llcast_ty = bx.cx().immediate_backend_type(cast);
-                                let llval = bx.pointercast(data_ptr, llcast_ty);
-                                OperandValue::Immediate(llval)
+                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr.
+                                OperandValue::Immediate(data_ptr)
                             }
                         } else {
                             bug!("unexpected non-pair operand");
@@ -736,13 +723,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
             mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
                 let operand = self.codegen_operand(bx, operand);
-                let lloperand = operand.immediate();
+                let val = operand.immediate();
 
                 let content_ty = self.monomorphize(content_ty);
                 let box_layout = bx.cx().layout_of(Ty::new_box(bx.tcx(), content_ty));
-                let llty_ptr = bx.cx().backend_type(box_layout);
 
-                let val = bx.pointercast(lloperand, llty_ptr);
                 OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index b72a1a07866..6fbf992eda9 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -140,8 +140,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
             MonoItem::Fn(instance) => {
                 format!("Fn({:?}, {})", instance.def, instance.args.as_ptr().addr())
             }
-            MonoItem::Static(id) => format!("Static({:?})", id),
-            MonoItem::GlobalAsm(id) => format!("GlobalAsm({:?})", id),
+            MonoItem::Static(id) => format!("Static({id:?})"),
+            MonoItem::GlobalAsm(id) => format!("GlobalAsm({id:?})"),
         }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 48c6c75bb1a..98e561b0aef 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -369,9 +369,9 @@ pub fn from_target_feature(
         // We allow comma separation to enable multiple features.
         target_features.extend(value.as_str().split(',').filter_map(|feature| {
             let Some(feature_gate) = supported_target_features.get(feature) else {
-                let msg = format!("the feature named `{}` is not valid for this target", feature);
+                let msg = format!("the feature named `{feature}` is not valid for this target");
                 let mut err = tcx.sess.struct_span_err(item.span(), msg);
-                err.span_label(item.span(), format!("`{}` is not valid for this target", feature));
+                err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
                 if let Some(stripped) = feature.strip_prefix('+') {
                     let valid = supported_target_features.contains_key(stripped);
                     if valid {
@@ -405,7 +405,7 @@ pub fn from_target_feature(
                     &tcx.sess.parse_sess,
                     feature_gate.unwrap(),
                     item.span(),
-                    format!("the target feature `{}` is currently unstable", feature),
+                    format!("the target feature `{feature}` is currently unstable"),
                 )
                 .emit();
             }
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 1991b55f191..0a02ca6b317 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -142,15 +142,6 @@ pub trait ExtraBackendMethods:
         target_features: &[String],
     ) -> TargetMachineFactoryFn<Self>;
 
-    fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
-    where
-        F: FnOnce() -> T,
-        F: Send + 'static,
-        T: Send + 'static,
-    {
-        std::thread::spawn(f)
-    }
-
     fn spawn_named_thread<F, T>(
         _time_trace: bool,
         name: String,
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 822c19155e3..4dff9c7684f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -36,7 +36,6 @@ pub trait ConstMethods<'tcx>: BackendTypes {
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
 
-    fn const_ptrcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value;
     fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value;
     fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index e64417e1a4a..dc3dbd9d819 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -26,8 +26,8 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
     fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type;
     fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
     fn type_kind(&self, ty: Self::Type) -> TypeKind;
-    fn type_ptr_to(&self, ty: Self::Type) -> Self::Type;
-    fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type;
+    fn type_ptr(&self) -> Self::Type;
+    fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type;
     fn element_type(&self, ty: Self::Type) -> Self::Type;
 
     /// Returns the number of elements in `self` if it is a LLVM vector type.
@@ -42,14 +42,6 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
 }
 
 pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
-    fn type_i8p(&self) -> Self::Type {
-        self.type_i8p_ext(AddressSpace::DATA)
-    }
-
-    fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type {
-        self.type_ptr_to_ext(self.type_i8(), address_space)
-    }
-
     fn type_int(&self) -> Self::Type {
         match &self.sess().target.c_int_width[..] {
             "16" => self.type_i16(),
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index a3b11ed4fe8..ecf5095d8a3 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -1,5 +1,5 @@
 use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
-use crate::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
+use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
 use crate::{CompiledModule, ModuleCodegen};
 
 use rustc_errors::{FatalError, Handler};
@@ -23,7 +23,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     /// for further optimization.
     fn run_fat_lto(
         cgcx: &CodegenContext<Self>,
-        modules: Vec<FatLTOInput<Self>>,
+        modules: Vec<FatLtoInput<Self>>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
     ) -> Result<LtoModuleCodegen<Self>, FatalError>;
     /// Performs thin LTO by performing necessary global analysis and returning two
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 91341ddacd1..ead172f04a3 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -208,13 +208,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let rest_ptr = first_ptr.offset(elem_size, self)?;
                     // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as
                     // that place might be more aligned than its type mandates (a `u8` array could
-                    // be 4-aligned if it sits at the right spot in a struct). Instead we use
-                    // `first.layout.align`, i.e., the alignment given by the type.
+                    // be 4-aligned if it sits at the right spot in a struct). We have to also factor
+                    // in element size.
                     self.mem_copy_repeatedly(
                         first_ptr,
-                        first.align,
+                        dest.align,
                         rest_ptr,
-                        first.layout.align.abi,
+                        dest.align.restrict_for_offset(elem_size),
                         elem_size,
                         length - 1,
                         /*nonoverlapping:*/ true,
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index 4567759c004..58704350706 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -16,22 +16,21 @@ const BASE_64: &[u8; MAX_BASE] =
 pub fn push_str(mut n: u128, base: usize, output: &mut String) {
     debug_assert!(base >= 2 && base <= MAX_BASE);
     let mut s = [0u8; 128];
-    let mut index = 0;
+    let mut index = s.len();
 
     let base = base as u128;
 
     loop {
+        index -= 1;
         s[index] = BASE_64[(n % base) as usize];
-        index += 1;
         n /= base;
 
         if n == 0 {
             break;
         }
     }
-    s[0..index].reverse();
 
-    output.push_str(str::from_utf8(&s[0..index]).unwrap());
+    output.push_str(str::from_utf8(&s[index..]).unwrap());
 }
 
 #[inline]
diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs
index d40172a2e2f..bc8a6b9eac0 100644
--- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs
+++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs
@@ -10,41 +10,17 @@ pub fn binary_search_slice<'d, E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, ke
 where
     K: Ord,
 {
-    let Ok(mid) = data.binary_search_by_key(key, &key_fn) else {
+    let size = data.len();
+    let start = data.partition_point(|x| key_fn(x) < *key);
+    // At this point `start` either points at the first entry with equal or
+    // greater key or is equal to `size` in case all elements have smaller keys
+    if start == size || key_fn(&data[start]) != *key {
         return &[];
     };
-    let size = data.len();
-
-    // We get back *some* element with the given key -- so do
-    // a galloping search backwards to find the *first* one.
-    let mut start = mid;
-    let mut previous = mid;
-    let mut step = 1;
-    loop {
-        start = start.saturating_sub(step);
-        if start == 0 || key_fn(&data[start]) != *key {
-            break;
-        }
-        previous = start;
-        step *= 2;
-    }
-    step = previous - start;
-    while step > 1 {
-        let half = step / 2;
-        let mid = start + half;
-        if key_fn(&data[mid]) != *key {
-            start = mid;
-        }
-        step -= half;
-    }
-    // adjust by one if we have overshot
-    if start < size && key_fn(&data[start]) != *key {
-        start += 1;
-    }
 
     // Now search forward to find the *last* one.
-    let mut end = mid;
-    let mut previous = mid;
+    let mut end = start;
+    let mut previous = start;
     let mut step = 1;
     loop {
         end = end.saturating_add(step).min(size);
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 9409057d484..60b343afbed 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -49,12 +49,11 @@ impl<K: Ord, V> SortedMap<K, V> {
     }
 
     #[inline]
-    pub fn insert(&mut self, key: K, mut value: V) -> Option<V> {
+    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
         match self.lookup_index_for(&key) {
             Ok(index) => {
                 let slot = unsafe { self.data.get_unchecked_mut(index) };
-                mem::swap(&mut slot.1, &mut value);
-                Some(value)
+                Some(mem::replace(&mut slot.1, value))
             }
             Err(index) => {
                 self.data.insert(index, (key, value));
diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs
index e36dded9e5e..314496ce9f0 100644
--- a/compiler/rustc_data_structures/src/sync/vec.rs
+++ b/compiler/rustc_data_structures/src/sync/vec.rs
@@ -43,37 +43,23 @@ impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {
 
 #[derive(Default)]
 pub struct AppendOnlyVec<T: Copy> {
-    #[cfg(not(parallel_compiler))]
-    vec: elsa::vec::FrozenVec<T>,
-    #[cfg(parallel_compiler)]
-    vec: elsa::sync::LockFreeFrozenVec<T>,
+    vec: parking_lot::RwLock<Vec<T>>,
 }
 
 impl<T: Copy> AppendOnlyVec<T> {
     pub fn new() -> Self {
-        Self {
-            #[cfg(not(parallel_compiler))]
-            vec: elsa::vec::FrozenVec::new(),
-            #[cfg(parallel_compiler)]
-            vec: elsa::sync::LockFreeFrozenVec::new(),
-        }
+        Self { vec: Default::default() }
     }
 
     pub fn push(&self, val: T) -> usize {
-        #[cfg(not(parallel_compiler))]
-        let i = self.vec.len();
-        #[cfg(not(parallel_compiler))]
-        self.vec.push(val);
-        #[cfg(parallel_compiler)]
-        let i = self.vec.push(val);
-        i
+        let mut v = self.vec.write();
+        let n = v.len();
+        v.push(val);
+        n
     }
 
     pub fn get(&self, i: usize) -> Option<T> {
-        #[cfg(not(parallel_compiler))]
-        return self.vec.get_copy(i);
-        #[cfg(parallel_compiler)]
-        return self.vec.get(i);
+        self.vec.read().get(i).copied()
     }
 
     pub fn iter_enumerated(&self) -> impl Iterator<Item = (usize, T)> + '_ {
diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs
index d61bb55be68..8c84daf4f16 100644
--- a/compiler/rustc_data_structures/src/sync/worker_local.rs
+++ b/compiler/rustc_data_structures/src/sync/worker_local.rs
@@ -116,7 +116,7 @@ pub struct WorkerLocal<T> {
 
 // This is safe because the `deref` call will return a reference to a `T` unique to each thread
 // or it will panic for threads without an associated local. So there isn't a need for `T` to do
-// it's own synchronization. The `verify` method on `RegistryId` has an issue where the the id
+// it's own synchronization. The `verify` method on `RegistryId` has an issue where the id
 // can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
 #[cfg(parallel_compiler)]
 unsafe impl<T: Send> Sync for WorkerLocal<T> {}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a49b842d9ff..77e2c900c0d 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -71,17 +71,17 @@ pub enum TranslationBundleError {
 impl fmt::Display for TranslationBundleError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {}", e),
+            TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {e}"),
             TranslationBundleError::ParseFtl(e) => {
-                write!(f, "could not parse ftl file: {}", e)
+                write!(f, "could not parse ftl file: {e}")
             }
-            TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e),
+            TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {e}"),
             TranslationBundleError::MissingLocale => write!(f, "missing locale directory"),
             TranslationBundleError::ReadLocalesDir(e) => {
-                write!(f, "could not read locales dir: {}", e)
+                write!(f, "could not read locales dir: {e}")
             }
             TranslationBundleError::ReadLocalesDirEntry(e) => {
-                write!(f, "could not read locales dir entry: {}", e)
+                write!(f, "could not read locales dir entry: {e}")
             }
             TranslationBundleError::LocaleIsNotDir => {
                 write!(f, "`$sysroot/share/locales/$locale` is not a directory")
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 9872b3bda1e..a88fba6dae6 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -157,10 +157,8 @@ impl AnnotateSnippetEmitterWriter {
             {
                 annotated_files.swap(0, pos);
             }
-            // owned: line source, line index, annotations
-            type Owned = (String, usize, Vec<crate::snippet::Annotation>);
-            let filename = source_map.filename_for_diagnostics(&primary_lo.file.name);
-            let origin = filename.to_string_lossy();
+            // owned: file name, line source, line index, annotations
+            type Owned = (String, String, usize, Vec<crate::snippet::Annotation>);
             let annotated_files: Vec<Owned> = annotated_files
                 .into_iter()
                 .flat_map(|annotated_file| {
@@ -169,7 +167,15 @@ impl AnnotateSnippetEmitterWriter {
                         .lines
                         .into_iter()
                         .map(|line| {
-                            (source_string(file.clone(), &line), line.line_index, line.annotations)
+                            // Ensure the source file is present before we try
+                            // to load a string from it.
+                            source_map.ensure_source_file_source_present(file.clone());
+                            (
+                                format!("{}", source_map.filename_for_diagnostics(&file.name)),
+                                source_string(file.clone(), &line),
+                                line.line_index,
+                                line.annotations,
+                            )
                         })
                         .collect::<Vec<Owned>>()
                 })
@@ -192,11 +198,11 @@ impl AnnotateSnippetEmitterWriter {
                 },
                 slices: annotated_files
                     .iter()
-                    .map(|(source, line_index, annotations)| {
+                    .map(|(file_name, source, line_index, annotations)| {
                         Slice {
                             source,
                             line_start: *line_index,
-                            origin: Some(&origin),
+                            origin: Some(&file_name),
                             // FIXME(#59346): Not really sure when `fold` should be true or false
                             fold: false,
                             annotations: annotations
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 961feba3250..44654571d43 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2145,7 +2145,7 @@ impl EmitterWriter {
                         &mut self.dst,
                         self.short_message,
                     ) {
-                        panic!("failed to emit error: {}", e)
+                        panic!("failed to emit error: {e}")
                     }
                 }
                 if !self.short_message {
@@ -2161,7 +2161,7 @@ impl EmitterWriter {
                             true,
                             None,
                         ) {
-                            panic!("failed to emit error: {}", err);
+                            panic!("failed to emit error: {err}");
                         }
                     }
                     for sugg in suggestions {
@@ -2180,7 +2180,7 @@ impl EmitterWriter {
                                     true,
                                     None,
                                 ) {
-                                    panic!("failed to emit error: {}", e);
+                                    panic!("failed to emit error: {e}");
                                 }
                             }
                             SuggestionStyle::HideCodeInline
@@ -2193,22 +2193,22 @@ impl EmitterWriter {
                                     &Level::Help,
                                     max_line_num_len,
                                 ) {
-                                    panic!("failed to emit error: {}", e);
+                                    panic!("failed to emit error: {e}");
                                 }
                             }
                         }
                     }
                 }
             }
-            Err(e) => panic!("failed to emit error: {}", e),
+            Err(e) => panic!("failed to emit error: {e}"),
         }
 
         let mut dst = self.dst.writable();
         match writeln!(dst) {
-            Err(e) => panic!("failed to emit error: {}", e),
+            Err(e) => panic!("failed to emit error: {e}"),
             _ => {
                 if let Err(e) = dst.flush() {
-                    panic!("failed to emit error: {}", e)
+                    panic!("failed to emit error: {e}")
                 }
             }
         }
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index f32d6b96b9b..55f7c485024 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -159,7 +159,7 @@ impl Emitter for JsonEmitter {
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
-            panic!("failed to print diagnostics: {:?}", e);
+            panic!("failed to print diagnostics: {e:?}");
         }
     }
 
@@ -172,7 +172,7 @@ impl Emitter for JsonEmitter {
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
-            panic!("failed to print notification: {:?}", e);
+            panic!("failed to print notification: {e:?}");
         }
     }
 
@@ -194,7 +194,7 @@ impl Emitter for JsonEmitter {
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
-            panic!("failed to print future breakage report: {:?}", e);
+            panic!("failed to print future breakage report: {e:?}");
         }
     }
 
@@ -208,7 +208,7 @@ impl Emitter for JsonEmitter {
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
-            panic!("failed to print unused externs: {:?}", e);
+            panic!("failed to print unused externs: {e:?}");
         }
     }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2181bd526eb..3d1639db4af 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1720,13 +1720,11 @@ impl HandlerInner {
                 (count, delayed_count, as_bug) => {
                     if delayed_count > 0 {
                         panic!(
-                            "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`",
-                            count, delayed_count, as_bug,
+                            "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={as_bug}`",
                         )
                     } else {
                         panic!(
-                            "aborting after {} errors due to `-Z treat-err-as-bug={}`",
-                            count, as_bug,
+                            "aborting after {count} errors due to `-Z treat-err-as-bug={as_bug}`",
                         )
                     }
                 }
@@ -1862,7 +1860,7 @@ pub fn add_elided_lifetime_in_path_suggestion(
     }
     let anon_lts = vec!["'_"; n].join(", ");
     let suggestion =
-        if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
+        if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
 
     diag.subdiagnostic(IndicateAnonymousLifetime {
         span: insertion_span.shrink_to_hi(),
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index aeb4f6e861b..8658cea137a 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -369,7 +369,7 @@ impl<'a> StripUnconfigured<'a> {
         let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
             orig_trees.next().unwrap().clone()
         else {
-            panic!("Bad tokens for attribute {:?}", attr);
+            panic!("Bad tokens for attribute {attr:?}");
         };
         let pound_span = pound_token.span;
 
@@ -379,7 +379,7 @@ impl<'a> StripUnconfigured<'a> {
             let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
                 orig_trees.next().unwrap().clone()
             else {
-                panic!("Bad tokens for attribute {:?}", attr);
+                panic!("Bad tokens for attribute {attr:?}");
             };
             trees.push(AttrTokenTree::Token(bang_token, Spacing::Alone));
         }
@@ -390,7 +390,7 @@ impl<'a> StripUnconfigured<'a> {
             Delimiter::Bracket,
             item.tokens
                 .as_ref()
-                .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
+                .unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
                 .to_attr_token_stream(),
         );
         trees.push(bracket_group);
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3b6db9fd39c..165c6d47c8a 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -803,7 +803,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             &self.cx.sess.parse_sess,
             sym::proc_macro_hygiene,
             span,
-            format!("custom attributes cannot be applied to {}", kind),
+            format!("custom attributes cannot be applied to {kind}"),
         )
         .emit();
     }
@@ -1707,7 +1707,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         &UNUSED_ATTRIBUTES,
                         attr.span,
                         self.cx.current_expansion.lint_node_id,
-                        format!("unused attribute `{}`", attr_name),
+                        format!("unused attribute `{attr_name}`"),
                         BuiltinLintDiagnostics::UnusedBuiltinAttribute {
                             attr_name,
                             macro_name: pprust::path_to_string(&call.path),
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 03de33dc854..e060375646c 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -257,7 +257,7 @@ pub(super) fn emit_frag_parse_err(
                         e.span_suggestion_verbose(
                             site_span,
                             "surround the macro invocation with `{}` to interpret the expansion as a statement",
-                            format!("{{ {}; }}", snippet),
+                            format!("{{ {snippet}; }}"),
                             Applicability::MaybeIncorrect,
                         );
                     }
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 34f998274e9..95f5bb2d2e2 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -593,7 +593,7 @@ fn check_ops_is_prefix(
             return;
         }
     }
-    buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{}`", name));
+    buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{name}`"));
 }
 
 /// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -626,7 +626,7 @@ fn ops_is_prefix(
         if i >= occurrence_ops.len() {
             let mut span = MultiSpan::from_span(span);
             span.push_span_label(binder.span, "expected repetition");
-            let message = format!("variable '{}' is still repeating at this depth", name);
+            let message = format!("variable '{name}' is still repeating at this depth");
             buffer_lint(sess, span, node_id, message);
             return;
         }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index f0e67cfd50e..05c0cd952b8 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -156,7 +156,7 @@ impl Display for MatcherLoc {
             MatcherLoc::MetaVarDecl { bind, kind, .. } => {
                 write!(f, "meta-variable `${bind}")?;
                 if let Some(kind) = kind {
-                    write!(f, ":{}", kind)?;
+                    write!(f, ":{kind}")?;
                 }
                 write!(f, "`")?;
                 Ok(())
@@ -723,7 +723,7 @@ impl TtParser {
             .iter()
             .map(|mp| match &matcher[mp.idx] {
                 MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
-                    format!("{} ('{}')", kind, bind)
+                    format!("{kind} ('{bind}')")
                 }
                 _ => unreachable!(),
             })
@@ -736,8 +736,8 @@ impl TtParser {
                 "local ambiguity when calling macro `{}`: multiple parsing options: {}",
                 self.macro_name,
                 match self.next_mps.len() {
-                    0 => format!("built-in NTs {}.", nts),
-                    n => format!("built-in NTs {} or {n} other option{s}.", nts, s = pluralize!(n)),
+                    0 => format!("built-in NTs {nts}."),
+                    n => format!("built-in NTs {nts} or {n} other option{s}.", s = pluralize!(n)),
                 }
             ),
         )
@@ -757,7 +757,7 @@ impl TtParser {
                     match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
                         Vacant(spot) => spot.insert(res.next().unwrap()),
                         Occupied(..) => {
-                            return Error(span, format!("duplicated bind name: {}", bind));
+                            return Error(span, format!("duplicated bind name: {bind}"));
                         }
                     };
                 } else {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 7398a124fdb..1b935058c04 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -249,7 +249,7 @@ fn expand_macro<'cx>(
                 trace_macros_note(&mut cx.expansions, sp, msg);
             }
 
-            let p = Parser::new(sess, tts, false, None);
+            let p = Parser::new(sess, tts, None);
 
             if is_local {
                 cx.resolver.record_macro_rule_usage(node_id, i);
@@ -257,7 +257,7 @@ fn expand_macro<'cx>(
 
             // Let the context choose how to interpret the result.
             // Weird, but useful for X-macros.
-            return Box::new(ParserAnyMacro {
+            Box::new(ParserAnyMacro {
                 parser: p,
 
                 // Pass along the original expansion site and the name of the macro
@@ -269,18 +269,17 @@ fn expand_macro<'cx>(
                 is_trailing_mac: cx.current_expansion.is_trailing_mac,
                 arm_span,
                 is_local,
-            });
+            })
         }
         Err(CanRetry::No(_)) => {
             debug!("Will not retry matching as an error was emitted already");
-            return DummyResult::any(sp);
+            DummyResult::any(sp)
         }
         Err(CanRetry::Yes) => {
-            // Retry and emit a better error below.
+            // Retry and emit a better error.
+            diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
         }
     }
-
-    diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
 }
 
 pub(super) enum CanRetry {
@@ -447,7 +446,7 @@ pub fn compile_declarative_macro(
 
     let create_parser = || {
         let body = macro_def.body.tokens.clone();
-        Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS)
+        Parser::new(&sess.parse_sess, body, rustc_parse::MACRO_ARGUMENTS)
     };
 
     let parser = create_parser();
@@ -457,8 +456,8 @@ pub fn compile_declarative_macro(
         match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
             Success(m) => m,
             Failure(()) => {
-                // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it with another one
-                // that gives us the information we need.
+                // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
+                // with another one that gives us the information we need.
                 // For this we need to reclone the macro body as the previous parser consumed it.
                 let retry_parser = create_parser();
 
@@ -554,7 +553,7 @@ pub fn compile_declarative_macro(
     let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
     match transparency_error {
         Some(TransparencyError::UnknownTransparency(value, span)) => {
-            diag.span_err(span, format!("unknown macro transparency: `{}`", value));
+            diag.span_err(span, format!("unknown macro transparency: `{value}`"));
         }
         Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => {
             diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
@@ -1197,7 +1196,7 @@ fn check_matcher_core<'tt>(
                                     may_be = may_be
                                 ),
                             );
-                            err.span_label(sp, format!("not allowed after `{}` fragments", kind));
+                            err.span_label(sp, format!("not allowed after `{kind}` fragments"));
 
                             if kind == NonterminalKind::PatWithOr
                                 && sess.edition.at_least_rust_2021()
@@ -1221,8 +1220,7 @@ fn check_matcher_core<'tt>(
                                 &[] => {}
                                 &[t] => {
                                     err.note(format!(
-                                        "only {} is allowed after `{}` fragments",
-                                        t, kind,
+                                        "only {t} is allowed after `{kind}` fragments",
                                     ));
                                 }
                                 ts => {
@@ -1407,9 +1405,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
 fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     match tt {
         mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(),
-        mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
-        mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
-        mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
+        mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
+        mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
+        mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
         _ => panic!(
             "{}",
             "unexpected mbe::TokenTree::{Sequence or Delimited} \
@@ -1418,6 +1416,11 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     }
 }
 
-pub(super) fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> {
-    Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS).recovery(recovery)
+pub(super) fn parser_from_cx(
+    sess: &ParseSess,
+    mut tts: TokenStream,
+    recovery: Recovery,
+) -> Parser<'_> {
+    tts.desugar_doc_comments();
+    Parser::new(sess, tts, rustc_parse::MACRO_ARGUMENTS).recovery(recovery)
 }
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index ac862ae8c4f..6546199f5e6 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -194,7 +194,7 @@ fn parse_tree<'a>(
                             Delimiter::Parenthesis => {}
                             _ => {
                                 let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
-                                let msg = format!("expected `(` or `{{`, found `{}`", tok);
+                                let msg = format!("expected `(` or `{{`, found `{tok}`");
                                 sess.span_diagnostic.span_err(delim_span.entire(), msg);
                             }
                         }
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 41b24407fa0..c617cd76e3c 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -95,7 +95,7 @@ impl base::AttrProcMacro for AttrProcMacro {
             |e| {
                 let mut err = ecx.struct_span_err(span, "custom attribute panicked");
                 if let Some(s) = e.as_str() {
-                    err.help(format!("message: {}", s));
+                    err.help(format!("message: {s}"));
                 }
                 err.emit()
             },
@@ -148,7 +148,7 @@ impl MultiItemModifier for DeriveProcMacro {
                 Err(e) => {
                     let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
                     if let Some(s) = e.as_str() {
-                        err.help(format!("message: {}", s));
+                        err.help(format!("message: {s}"));
                     }
                     err.emit();
                     return ExpandResult::Ready(vec![]);
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ac73b5d72b7..2dc9b51a37e 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -622,7 +622,7 @@ impl server::SourceFile for Rustc<'_, '_> {
 impl server::Span for Rustc<'_, '_> {
     fn debug(&mut self, span: Self::Span) -> String {
         if self.ecx.ecfg.span_debug {
-            format!("{:?}", span)
+            format!("{span:?}")
         } else {
             format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
         }
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 22380a52104..bbc3d291e20 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -449,7 +449,7 @@ declare_features! (
     // Allows setting the threshold for the `large_assignments` lint.
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allow to have type alias types for inter-crate use.
-    (active, lazy_type_alias, "1.72.0", Some(112792), None),
+    (incomplete, lazy_type_alias, "1.72.0", Some(112792), None),
     /// Allows `if/while p && let q = r && ...` chains.
     (active, let_chains, "1.37.0", Some(53667), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 84452979aa5..73627a818e5 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -576,7 +576,6 @@ fn find_and_apply_rpit_args<'tcx>(
     struct Visitor<'tcx> {
         tcx: TyCtxt<'tcx>,
         opaque: DefId,
-        function: DefId,
         seen: FxHashSet<DefId>,
     }
     impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
@@ -601,19 +600,6 @@ fn find_and_apply_rpit_args<'tcx>(
                         }
                     }
                 }
-                ty::Alias(ty::Projection, alias) => {
-                    if self.tcx.is_impl_trait_in_trait(alias.def_id)
-                        && self.tcx.impl_trait_in_trait_parent_fn(alias.def_id) == self.function
-                    {
-                        // If we're lowering to associated item, install the opaque type which is just
-                        // the `type_of` of the trait's associated item. If we're using the old lowering
-                        // strategy, then just reinterpret the associated type like an opaque :^)
-                        self.tcx
-                            .type_of(alias.def_id)
-                            .instantiate(self.tcx, alias.args)
-                            .visit_with(self)?;
-                    }
-                }
                 ty::Alias(ty::Weak, alias) => {
                     self.tcx
                         .type_of(alias.def_id)
@@ -627,7 +613,7 @@ fn find_and_apply_rpit_args<'tcx>(
         }
     }
     if let ControlFlow::Break(args) =
-        ret.visit_with(&mut Visitor { tcx, function, opaque, seen: Default::default() })
+        ret.visit_with(&mut Visitor { tcx, opaque, seen: Default::default() })
     {
         trace!(?args);
         trace!("expected: {hidden_ty:#?}");
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index e076b1fc68c..064021b1ea4 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -521,6 +521,10 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)),
         sym::simd_arith_offset => (2, vec![param(0), param(1)], param(0)),
         sym::simd_neg
+        | sym::simd_bswap
+        | sym::simd_bitreverse
+        | sym::simd_ctlz
+        | sym::simd_cttz
         | sym::simd_fsqrt
         | sym::simd_fsin
         | sym::simd_fcos
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 0e99df4f581..ad886ce82b1 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -246,8 +246,11 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         // `ForeignItem`s are handled separately.
         hir::ItemKind::ForeignMod { .. } => {}
         hir::ItemKind::TyAlias(hir_ty, ..) => {
-            if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
-                // Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
+            if tcx.features().lazy_type_alias
+                || tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
+            {
+                // Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
+                // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
                 check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
             }
         }
@@ -284,6 +287,17 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
     };
     check_object_unsafe_self_trait_by_name(tcx, trait_item);
     check_associated_item(tcx, def_id, span, method_sig);
+
+    if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
+        for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) {
+            check_associated_item(
+                tcx,
+                assoc_ty_def_id.expect_local(),
+                tcx.def_span(assoc_ty_def_id),
+                None,
+            );
+        }
+    }
 }
 
 /// Require that the user writes where clauses on GATs for the implicit
@@ -1466,13 +1480,6 @@ fn check_fn_or_method<'tcx>(
 
     check_where_clauses(wfcx, span, def_id);
 
-    check_return_position_impl_trait_in_trait_bounds(
-        wfcx,
-        def_id,
-        sig.output(),
-        hir_decl.output.span(),
-    );
-
     if sig.abi == Abi::RustCall {
         let span = tcx.def_span(def_id);
         let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
@@ -1507,87 +1514,6 @@ fn check_fn_or_method<'tcx>(
     }
 }
 
-/// Basically `check_associated_type_bounds`, but separated for now and should be
-/// deduplicated when RPITITs get lowered into real associated items.
-#[tracing::instrument(level = "trace", skip(wfcx))]
-fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
-    wfcx: &WfCheckingCtxt<'_, 'tcx>,
-    fn_def_id: LocalDefId,
-    fn_output: Ty<'tcx>,
-    span: Span,
-) {
-    let tcx = wfcx.tcx();
-    let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else {
-        return;
-    };
-    if assoc_item.container != ty::AssocItemContainer::TraitContainer {
-        return;
-    }
-    fn_output.visit_with(&mut ImplTraitInTraitFinder {
-        wfcx,
-        fn_def_id,
-        depth: ty::INNERMOST,
-        seen: FxHashSet::default(),
-    });
-}
-
-// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
-// strategy, we can't just call `check_associated_item` on the new RPITITs,
-// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
-// That's because we need to check that the bounds of the RPITIT hold using
-// the special args that we create during opaque type lowering, otherwise we're
-// getting a bunch of early bound and free regions mixed up... Haven't looked too
-// deep into this, though.
-struct ImplTraitInTraitFinder<'a, 'tcx> {
-    wfcx: &'a WfCheckingCtxt<'a, 'tcx>,
-    fn_def_id: LocalDefId,
-    depth: ty::DebruijnIndex,
-    seen: FxHashSet<DefId>,
-}
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
-    type BreakTy = !;
-
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> {
-        let tcx = self.wfcx.tcx();
-        if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
-            && self.seen.insert(unshifted_opaque_ty.def_id)
-            && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
-            && let origin = tcx.opaque_type_origin(opaque_def_id)
-            && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin
-            && source == self.fn_def_id
-        {
-            let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
-                match re.kind() {
-                    ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
-                    r => bug!("unexpected region: {r:?}"),
-                }
-            });
-            for (bound, bound_span) in tcx
-                .explicit_item_bounds(opaque_ty.def_id)
-                .iter_instantiated_copied(tcx, opaque_ty.args)
-            {
-                let bound = self.wfcx.normalize(bound_span, None, bound);
-                self.wfcx.register_obligations(traits::wf::predicate_obligations(
-                    self.wfcx.infcx,
-                    self.wfcx.param_env,
-                    self.wfcx.body_def_id,
-                    bound.as_predicate(),
-                    bound_span,
-                ));
-                // Set the debruijn index back to innermost here, since we already eagerly
-                // shifted the args that we use to generate these bounds. This is unfortunately
-                // subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`,
-                // but that function doesn't actually need to normalize the bound it's visiting
-                // (whereas we have to do so here)...
-                let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST);
-                bound.visit_with(self);
-                self.depth = old_depth;
-            }
-        }
-        ty.super_visit_with(self)
-    }
-}
-
 const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
      `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
      of the previous types except `Self`)";
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 758e9dc7230..4b7743fae53 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -3,7 +3,7 @@ use crate::astconv::{AstConv, PredicateFilter};
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
@@ -113,7 +113,7 @@ pub(super) fn explicit_item_bounds(
             ..
         }) => associated_type_bounds(tcx, def_id, bounds, *span),
         hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
+            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
             span,
             ..
         }) => {
@@ -121,6 +121,27 @@ pub(super) fn explicit_item_bounds(
             let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
             opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
         }
+        // Since RPITITs are astconv'd as projections in `ast_ty_to_ty`, when we're asking
+        // for the item bounds of the *opaques* in a trait's default method signature, we
+        // need to map these projections back to opaques.
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
+            span,
+            ..
+        }) => {
+            let (hir::OpaqueTyOrigin::FnReturn(fn_def_id)
+            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin
+            else {
+                bug!()
+            };
+            let args = GenericArgs::identity_for_item(tcx, def_id);
+            let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
+            tcx.arena.alloc_slice(
+                &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
+                    .to_vec()
+                    .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
+            )
+        }
         hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
         _ => bug!("item_bounds called on {:?}", def_id),
     };
@@ -135,3 +156,26 @@ pub(super) fn item_bounds(
         tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
     })
 }
+
+struct AssocTyToOpaque<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    fn_def_id: DefId,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
+            && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. })
+                = self.tcx.opt_rpitit_info(projection_ty.def_id)
+            && fn_def_id == self.fn_def_id
+        {
+            self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
+        } else {
+            ty
+        }
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 119ed2fa408..d5f03a6aaed 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -558,10 +558,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     {
                         let pred = clause.kind().rebind(match clause.kind().skip_binder() {
                             ty::ClauseKind::Trait(trait_pred) => {
-                                // FIXME(rpitit): This will need to be fixed when we move to associated types
                                 assert!(matches!(
                                     *trait_pred.trait_ref.self_ty().kind(),
-                                    ty::Alias(_, ty::AliasTy { def_id, args: alias_args, .. })
+                                    ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
                                     if def_id == rpit_def_id && args == alias_args
                                 ));
                                 ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
@@ -569,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ty::ClauseKind::Projection(mut proj_pred) => {
                                 assert!(matches!(
                                     *proj_pred.projection_ty.self_ty().kind(),
-                                    ty::Alias(_, ty::AliasTy { def_id, args: alias_args, .. })
+                                    ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
                                     if def_id == rpit_def_id && args == alias_args
                                 ));
                                 proj_pred = proj_pred.with_self_ty(self.tcx, ty);
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index ca3b595d238..0624a4baf79 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -723,11 +723,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return None,
-            ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
-                .tcx
-                .explicit_item_bounds(proj.def_id)
-                .iter_instantiated_copied(self.tcx, proj.args)
-                .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
                 "async fn generator return type not an inference variable: {ret_ty}"
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index b059db23bb4..cfedcee9956 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -443,9 +443,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
                 // We add an edge to the hir_id of the expression/block we are breaking out of, and
                 // then in process_deferred_edges we will map this hir_id to its PostOrderId, which
                 // will refer to the end of the block due to the post order traversal.
-                self.find_target_expression_from_destination(destination).map_or((), |target| {
+                if let Ok(target) = self.find_target_expression_from_destination(destination) {
                     self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
-                });
+                }
 
                 if let Some(value) = value {
                     self.visit_expr(value);
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index 50a3bbf49d5..29413f08012 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -150,9 +150,10 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
             hir.node_to_string(diag_expr_id),
             hir.node_to_string(parent)
         );
-        place_with_id
-            .try_into()
-            .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+
+        if let Ok(tracked_value) = place_with_id.try_into() {
+            self.mark_consumed(parent, tracked_value)
+        }
     }
 
     fn borrow(
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 1eae258c1b2..a283cd1abf5 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -4,7 +4,7 @@ use super::method::MethodCallee;
 use super::{has_expected_num_generic_args, FnCtxt};
 use crate::Expectation;
 use rustc_ast as ast;
-use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
+use rustc_errors::{self, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::ObligationCauseCode;
@@ -380,33 +380,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
 
-                let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
-                    if self
-                        .lookup_op_method(
-                            lhs_deref_ty,
-                            Some((rhs_expr, rhs_ty)),
-                            Op::Binary(op, is_assign),
-                            expected,
-                        )
-                        .is_ok()
-                    {
-                        let msg = format!(
-                            "`{}{}` can be used on `{}` if you dereference the left-hand side",
-                            op.node.as_str(),
-                            match is_assign {
-                                IsAssign::Yes => "=",
-                                IsAssign::No => "",
-                            },
-                            lhs_deref_ty,
-                        );
-                        err.span_suggestion_verbose(
-                            lhs_expr.span.shrink_to_lo(),
-                            msg,
-                            "*",
-                            rustc_errors::Applicability::MachineApplicable,
-                        );
-                    }
-                };
+                let suggest_deref_binop =
+                    |err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| {
+                        if self
+                            .lookup_op_method(
+                                lhs_deref_ty,
+                                Some((rhs_expr, rhs_ty)),
+                                Op::Binary(op, is_assign),
+                                expected,
+                            )
+                            .is_ok()
+                        {
+                            let msg = format!(
+                                "`{}{}` can be used on `{}` if you dereference the left-hand side",
+                                op.node.as_str(),
+                                match is_assign {
+                                    IsAssign::Yes => "=",
+                                    IsAssign::No => "",
+                                },
+                                lhs_deref_ty,
+                            );
+                            err.span_suggestion_verbose(
+                                lhs_expr.span.shrink_to_lo(),
+                                msg,
+                                "*",
+                                rustc_errors::Applicability::MachineApplicable,
+                            );
+                        }
+                    };
+
+                let suggest_different_borrow =
+                    |err: &mut DiagnosticBuilder<'_, _>,
+                     lhs_adjusted_ty,
+                     lhs_new_mutbl: Option<ast::Mutability>,
+                     rhs_adjusted_ty,
+                     rhs_new_mutbl: Option<ast::Mutability>| {
+                        if self
+                            .lookup_op_method(
+                                lhs_adjusted_ty,
+                                Some((rhs_expr, rhs_adjusted_ty)),
+                                Op::Binary(op, is_assign),
+                                expected,
+                            )
+                            .is_ok()
+                        {
+                            let op_str = op.node.as_str();
+                            err.note(format!("an implementation for `{lhs_adjusted_ty} {op_str} {rhs_adjusted_ty}` exists"));
+
+                            if let Some(lhs_new_mutbl) = lhs_new_mutbl
+                                && let Some(rhs_new_mutbl) = rhs_new_mutbl
+                                && lhs_new_mutbl.is_not()
+                                && rhs_new_mutbl.is_not() {
+                                err.multipart_suggestion_verbose(
+                                    "consider reborrowing both sides",
+                                    vec![
+                                        (lhs_expr.span.shrink_to_lo(), "&*".to_string()),
+                                        (rhs_expr.span.shrink_to_lo(), "&*".to_string())
+                                    ],
+                                    rustc_errors::Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| {
+                                    // Can reborrow (&mut -> &)
+                                    if new_mutbl.is_not() {
+                                        err.span_suggestion_verbose(
+                                            sp.shrink_to_lo(),
+                                            "consider reborrowing this side",
+                                            "&*",
+                                            rustc_errors::Applicability::MachineApplicable,
+                                        );
+                                    // Works on &mut but have &
+                                    } else {
+                                        err.span_help(
+                                            sp,
+                                            "consider making this expression a mutable borrow",
+                                        );
+                                    }
+                                };
+
+                                if let Some(lhs_new_mutbl) = lhs_new_mutbl {
+                                    suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
+                                }
+                                if let Some(rhs_new_mutbl) = rhs_new_mutbl {
+                                    suggest_new_borrow(rhs_new_mutbl, rhs_expr.span);
+                                }
+                            }
+                        }
+                    };
 
                 let is_compatible_after_call = |lhs_ty, rhs_ty| {
                     self.lookup_op_method(
@@ -429,15 +489,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else if is_assign == IsAssign::Yes
                     && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
                 {
-                    suggest_deref_binop(lhs_deref_ty);
+                    suggest_deref_binop(&mut err, lhs_deref_ty);
                 } else if is_assign == IsAssign::No
-                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind()
+                    && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
                 {
                     if self.type_is_copy_modulo_regions(
                         self.param_env,
                         *lhs_deref_ty,
                     ) {
-                        suggest_deref_binop(*lhs_deref_ty);
+                        suggest_deref_binop(&mut err, *lhs_deref_ty);
+                    } else {
+                        let lhs_inv_mutbl = mutbl.invert();
+                        let lhs_inv_mutbl_ty = Ty::new_ref(
+                            self.tcx,
+                            *region,
+                            ty::TypeAndMut {
+                                ty: *lhs_deref_ty,
+                                mutbl: lhs_inv_mutbl,
+                            },
+                        );
+
+                        suggest_different_borrow(
+                            &mut err,
+                            lhs_inv_mutbl_ty,
+                            Some(lhs_inv_mutbl),
+                            rhs_ty,
+                            None,
+                        );
+
+                        if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
+                            let rhs_inv_mutbl = mutbl.invert();
+                            let rhs_inv_mutbl_ty = Ty::new_ref(
+                                self.tcx,
+                                *region,
+                                ty::TypeAndMut {
+                                    ty: *rhs_deref_ty,
+                                    mutbl: rhs_inv_mutbl,
+                                },
+                            );
+
+                            suggest_different_borrow(
+                                &mut err,
+                                lhs_ty,
+                                None,
+                                rhs_inv_mutbl_ty,
+                                Some(rhs_inv_mutbl),
+                            );
+                            suggest_different_borrow(
+                                &mut err,
+                                lhs_inv_mutbl_ty,
+                                Some(lhs_inv_mutbl),
+                                rhs_inv_mutbl_ty,
+                                Some(rhs_inv_mutbl),
+                            );
+                        }
                     }
                 } else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
                     is_compatible_after_call(lhs_ty, rhs_ty)
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 4d236a86dda..d8eb8c71b5e 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -755,7 +755,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             match binding_parent {
                 // Check that there is explicit type (ie this is not a closure param with inferred type)
                 // so we don't suggest moving something to the type that does not exist
-                hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => {
+                hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
                     err.multipart_suggestion_verbose(
                         format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
                         vec![
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 52a84b204d0..5e7ae3ecdb8 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -241,16 +241,16 @@ fn dump_graph(query: &DepGraphQuery) {
 
     {
         // dump a .txt file with just the edges:
-        let txt_path = format!("{}.txt", path);
+        let txt_path = format!("{path}.txt");
         let mut file = BufWriter::new(File::create(&txt_path).unwrap());
         for (source, target) in &edges {
-            write!(file, "{:?} -> {:?}\n", source, target).unwrap();
+            write!(file, "{source:?} -> {target:?}\n").unwrap();
         }
     }
 
     {
         // dump a .dot file in graphviz format:
-        let dot_path = format!("{}.dot", path);
+        let dot_path = format!("{path}.dot");
         let mut v = Vec::new();
         dot::render(&GraphvizDepGraph(nodes, edges), &mut v).unwrap();
         fs::write(dot_path, v).unwrap();
@@ -285,7 +285,7 @@ impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
         dot::Id::new("DependencyGraph").unwrap()
     }
     fn node_id(&self, n: &DepKind) -> dot::Id<'_> {
-        let s: String = format!("{:?}", n)
+        let s: String = format!("{n:?}")
             .chars()
             .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
             .collect();
@@ -293,7 +293,7 @@ impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
         dot::Id::new(s).unwrap()
     }
     fn node_label(&self, n: &DepKind) -> dot::LabelText<'_> {
-        dot::LabelText::label(format!("{:?}", n))
+        dot::LabelText::label(format!("{n:?}"))
     }
 }
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index f9cd01fd80d..5dd06c6ca4f 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -300,7 +300,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
             },
             _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirty {
                 span: attr.span,
-                kind: format!("{:?}", node),
+                kind: format!("{node:?}"),
             }),
         };
         let labels =
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 929a1e149b6..1111a1a17e2 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -427,13 +427,11 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
     if sess.opts.unstable_opts.incremental_info {
         eprintln!(
             "[incremental] session directory: \
-                  {} files hard-linked",
-            files_linked
+                  {files_linked} files hard-linked"
         );
         eprintln!(
             "[incremental] session directory: \
-                 {} files copied",
-            files_copied
+                 {files_copied} files copied"
         );
     }
 
@@ -604,7 +602,7 @@ fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId
 
     let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
 
-    let crate_name = format!("{}-{}", crate_name, stable_crate_id);
+    let crate_name = format!("{crate_name}-{stable_crate_id}");
     incr_dir.join(crate_name)
 }
 
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 1ffa8633afd..a7e045e1e89 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -210,10 +210,8 @@ impl<'a> SourceKindMultiSuggestion<'a> {
             _ => ("", ""),
         };
         let (start_span, start_span_code, end_span) = match should_wrap_expr {
-            Some(end_span) => {
-                (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
-            }
-            None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
+            Some(end_span) => (data.span(), format!("{arrow}{ty_info}{post}{{ "), Some(end_span)),
+            None => (data.span(), format!("{arrow}{ty_info}{post}"), None),
         };
         Self::ClosureReturn { start_span, start_span_code, end_span }
     }
@@ -404,9 +402,9 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
             debug!(?lifetime_sub.ident.span);
             let make_suggestion = |ident: Ident| {
                 let sugg = if ident.name == kw::Empty {
-                    format!("{}, ", suggestion_param_name)
+                    format!("{suggestion_param_name}, ")
                 } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
-                    format!("{} ", suggestion_param_name)
+                    format!("{suggestion_param_name} ")
                 } else {
                     suggestion_param_name.clone()
                 };
@@ -419,9 +417,9 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
                 let new_param_suggestion = if let Some(first) =
                     generics.params.iter().find(|p| !p.name.ident().span.is_empty())
                 {
-                    (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+                    (first.span.shrink_to_lo(), format!("{suggestion_param_name}, "))
                 } else {
-                    (generics.span, format!("<{}>", suggestion_param_name))
+                    (generics.span, format!("<{suggestion_param_name}>"))
                 };
 
                 suggestions.push(new_param_suggestion);
@@ -1320,7 +1318,7 @@ impl AddToDiagnostic for SuggestTuplePatternMany {
             message,
             self.compatible_variants.into_iter().map(|variant| {
                 vec![
-                    (self.cause_span.shrink_to_lo(), format!("{}(", variant)),
+                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
                     (self.cause_span.shrink_to_hi(), ")".to_string()),
                 ]
             }),
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 7328241dfbc..bd168f047fa 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -80,7 +80,7 @@ impl<'a> DescriptionCtx<'a> {
             // We shouldn't really be having unification failures with ReVar
             // and ReLateBound though.
             ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
-                (alt_span, "revar", format!("{:?}", region))
+                (alt_span, "revar", format!("{region:?}"))
             }
         };
         Some(DescriptionCtx { span, kind, arg })
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 1fd5d2adf80..54d901f20da 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -205,7 +205,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                 // `delay_span_bug` to allow type error over an ICE.
                 canonicalizer.tcx.sess.delay_span_bug(
                     rustc_span::DUMMY_SP,
-                    format!("unexpected region in query response: `{:?}`", r),
+                    format!("unexpected region in query response: `{r:?}`"),
                 );
                 r
             }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 38f8ad744a6..ddc8e7e50eb 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -177,7 +177,7 @@ impl<'tcx> InferCtxt<'tcx> {
             self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
                 self.tcx.sess.delay_span_bug(
                     DUMMY_SP,
-                    format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
+                    format!("cannot relate consts of different types (a={a:?}, b={b:?})",),
                 )
             })
         });
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index c000f988aa2..5a78790ec6e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -238,7 +238,7 @@ fn msg_span_from_named_region<'tcx>(
                         let text = if name == kw::UnderscoreLifetime {
                             "the anonymous lifetime as defined here".to_string()
                         } else {
-                            format!("the lifetime `{}` as defined here", name)
+                            format!("the lifetime `{name}` as defined here")
                         };
                         (text, Some(span))
                     }
@@ -250,7 +250,7 @@ fn msg_span_from_named_region<'tcx>(
                         })
                     ),
                     _ => (
-                        format!("the lifetime `{}` as defined here", region),
+                        format!("the lifetime `{region}` as defined here"),
                         Some(tcx.def_span(scope)),
                     ),
                 }
@@ -280,7 +280,7 @@ fn emit_msg_span(
     span: Option<Span>,
     suffix: &str,
 ) {
-    let message = format!("{}{}{}", prefix, description, suffix);
+    let message = format!("{prefix}{description}{suffix}");
 
     if let Some(span) = span {
         err.span_note(span, message);
@@ -296,7 +296,7 @@ fn label_msg_span(
     span: Option<Span>,
     suffix: &str,
 ) {
-    let message = format!("{}{}{}", prefix, description, suffix);
+    let message = format!("{prefix}{description}{suffix}");
 
     if let Some(span) = span {
         err.span_label(span, message);
@@ -333,7 +333,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             explain_free_region(
                 tcx,
                 &mut err,
-                &format!("hidden type `{}` captures ", hidden_ty),
+                &format!("hidden type `{hidden_ty}` captures "),
                 hidden_region,
                 "",
             );
@@ -345,7 +345,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                     fn_returns,
                     hidden_region.to_string(),
                     None,
-                    format!("captures `{}`", hidden_region),
+                    format!("captures `{hidden_region}`"),
                     None,
                     Some(reg_info.def_id),
                 )
@@ -373,7 +373,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             note_and_explain_region(
                 tcx,
                 &mut err,
-                &format!("hidden type `{}` captures ", hidden_ty),
+                &format!("hidden type `{hidden_ty}` captures "),
                 hidden_region,
                 "",
                 None,
@@ -716,7 +716,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     {
                         err.span_label(span, format!("this is an iterator with items of type `{}`", args.type_at(0)));
                     } else {
-                    err.span_label(span, format!("this expression has type `{}`", ty));
+                    err.span_label(span, format!("this expression has type `{ty}`"));
                 }
                 }
                 if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
@@ -726,7 +726,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     err.span_suggestion(
                         span,
                         "consider dereferencing the boxed value",
-                        format!("*{}", snippet),
+                        format!("*{snippet}"),
                         Applicability::MachineApplicable,
                     );
                 }
@@ -785,13 +785,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     if prior_arms.len() <= 4 {
                         for sp in prior_arms {
                             any_multiline_arm |= source_map.is_multiline(*sp);
-                            err.span_label(*sp, format!("this is found to be of type `{}`", t));
+                            err.span_label(*sp, format!("this is found to be of type `{t}`"));
                         }
                     } else if let Some(sp) = prior_arms.last() {
                         any_multiline_arm |= source_map.is_multiline(*sp);
                         err.span_label(
                             *sp,
-                            format!("this and all prior arms are found to be of type `{}`", t),
+                            format!("this and all prior arms are found to be of type `{t}`"),
                         );
                     }
                     let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
@@ -1661,7 +1661,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ..
                 })) = values
                 {
-                    Cow::from(format!("expected this to be `{}`", expected))
+                    Cow::from(format!("expected this to be `{expected}`"))
                 } else {
                     terr.to_string(self.tcx)
                 };
@@ -2368,13 +2368,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
 
         let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
+            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
             GenericKind::Alias(ref p) => match p.kind(self.tcx) {
                 ty::AliasKind::Projection | ty::AliasKind::Inherent => {
-                    format!("the associated type `{}`", p)
+                    format!("the associated type `{p}`")
                 }
-                ty::AliasKind::Weak => format!("the type alias `{}`", p),
-                ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
+                ty::AliasKind::Weak => format!("the type alias `{p}`"),
+                ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
             },
         };
 
@@ -2388,7 +2388,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 span,
                 impl_item_def_id,
                 trait_item_def_id,
-                &format!("`{}: {}`", bound_kind, sub),
+                &format!("`{bound_kind}: {sub}`"),
             );
         }
 
@@ -2402,7 +2402,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             let msg = "consider adding an explicit lifetime bound";
             if let Some((sp, has_lifetimes)) = type_param_span {
                 let suggestion =
-                    if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
+                    if has_lifetimes { format!(" + {sub}") } else { format!(": {sub}") };
                 let mut suggestions = vec![(sp, suggestion)];
                 for add_lt_sugg in add_lt_suggs.into_iter().flatten() {
                     suggestions.push(add_lt_sugg);
@@ -2413,7 +2413,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     Applicability::MaybeIncorrect, // Issue #41966
                 );
             } else {
-                let consider = format!("{} `{}: {}`...", msg, bound_kind, sub);
+                let consider = format!("{msg} `{bound_kind}: {sub}`...");
                 err.help(consider);
             }
         }
@@ -2422,13 +2422,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
                 let msg = "consider introducing an explicit lifetime bound";
                 if let Some((sp, has_lifetimes)) = type_param_span {
-                    let suggestion = if has_lifetimes {
-                        format!(" + {}", new_lt)
-                    } else {
-                        format!(": {}", new_lt)
-                    };
+                    let suggestion =
+                        if has_lifetimes { format!(" + {new_lt}") } else { format!(": {new_lt}") };
                     let mut sugg =
-                        vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
+                        vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {new_lt}"))];
                     for lt in add_lt_suggs.clone().into_iter().flatten() {
                         sugg.push(lt);
                         sugg.rotate_right(1);
@@ -2508,7 +2505,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     "{} may not live long enough",
                     labeled_user_string
                 );
-                let pred = format!("{}: {}", bound_kind, sub);
+                let pred = format!("{bound_kind}: {sub}");
                 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
                 err.span_suggestion(
                     generics.tail_span_for_predicate_suggestion(),
@@ -2564,7 +2561,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 note_and_explain_region(
                     self.tcx,
                     &mut err,
-                    &format!("{} must be valid for ", labeled_user_string),
+                    &format!("{labeled_user_string} must be valid for "),
                     sub,
                     "...",
                     None,
@@ -2814,10 +2811,10 @@ impl<'tcx> InferCtxt<'tcx> {
                 br_string(br),
                 self.tcx.associated_item(def_id).name
             ),
-            infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
+            infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{name}`"),
             infer::UpvarRegion(ref upvar_id, _) => {
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                format!(" for capture of `{}` by closure", var_name)
+                format!(" for capture of `{var_name}` by closure")
             }
             infer::Nll(..) => bug!("NLL variable found in lexical phase"),
         };
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 36b56fe782c..9dfa45858a7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -246,7 +246,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
     } else {
         format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None))
     };
-    format!("fn({}){}", args, ret)
+    format!("fn({args}){ret}")
 }
 
 impl<'tcx> InferCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 40dc6497611..d08b6ba5e47 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -235,10 +235,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         let arg = match param.param.pat.simple_ident() {
-            Some(simple_ident) => format!("argument `{}`", simple_ident),
+            Some(simple_ident) => format!("argument `{simple_ident}`"),
             None => "the argument".to_string(),
         };
-        let captures = format!("captures data from {}", arg);
+        let captures = format!("captures data from {arg}");
         suggest_new_region_bound(
             tcx,
             &mut err,
@@ -269,11 +269,11 @@ pub fn suggest_new_region_bound(
     // FIXME: account for the need of parens in `&(dyn Trait + '_)`
     let consider = "consider changing";
     let declare = "to declare that";
-    let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+    let explicit = format!("you can add an explicit `{lifetime_name}` lifetime bound");
     let explicit_static =
-        arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
+        arg.map(|arg| format!("explicit `'static` bound to the lifetime of {arg}"));
     let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
-    let plus_lt = format!(" + {}", lifetime_name);
+    let plus_lt = format!(" + {lifetime_name}");
     for fn_return in fn_returns {
         if fn_return.span.desugaring_kind().is_some() {
             // Skip `async` desugaring `impl Future`.
@@ -383,12 +383,7 @@ pub fn suggest_new_region_bound(
                 if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
                     err.span_suggestion_verbose(
                         fn_return.span.shrink_to_hi(),
-                        format!(
-                            "{declare} the trait object {captures}, {explicit}",
-                            declare = declare,
-                            captures = captures,
-                            explicit = explicit,
-                        ),
+                        format!("{declare} the trait object {captures}, {explicit}",),
                         &plus_lt,
                         Applicability::MaybeIncorrect,
                     );
@@ -400,7 +395,7 @@ pub fn suggest_new_region_bound(
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             lt.ident.span,
-                            format!("{} the trait object's {}", consider, explicit_static),
+                            format!("{consider} the trait object's {explicit_static}"),
                             &lifetime_name,
                             Applicability::MaybeIncorrect,
                         );
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 8cd1b82130b..8d3cd23b7fa 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -227,7 +227,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     span,
                     impl_item_def_id,
                     trait_item_def_id,
-                    &format!("`{}: {}`", sup, sub),
+                    &format!("`{sup}: {sub}`"),
                 );
                 // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
                 if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
@@ -251,7 +251,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
                     err.span_label(
                         trait_item_span,
-                        format!("definition of `{}` from trait", item_name),
+                        format!("definition of `{item_name}` from trait"),
                     );
                 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 8e3f6b97e8f..372539d73b1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -47,7 +47,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             diag.span_suggestion(
                                 sp,
                                 "use a float literal",
-                                format!("{}.0", snippet),
+                                format!("{snippet}.0"),
                                 MachineApplicable,
                             );
                         }
@@ -134,7 +134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                             if matched_end_of_args {
                                 // Append suggestion to the end of our args
-                                let path = format!(", {}{} = {}",item_name, item_args, p);
+                                let path = format!(", {item_name}{item_args} = {p}");
                                 note = !suggest_constraining_type_param(
                                     tcx,
                                     generics,
@@ -148,7 +148,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 // Suggest adding a bound to an existing trait
                                 // or if the trait doesn't exist, add the trait
                                 // and the suggested bounds.
-                                let path = format!("<{}{} = {}>", item_name, item_args, p);
+                                let path = format!("<{item_name}{item_args} = {p}>");
                                 note = !suggest_constraining_type_param(
                                     tcx,
                                     generics,
@@ -213,8 +213,7 @@ impl<T> Trait<T> for X {
                         }
                         diag.help(format!(
                             "every closure has a distinct type and so could not always match the \
-                             caller-chosen type of parameter `{}`",
-                            p
+                             caller-chosen type of parameter `{p}`"
                         ));
                     }
                     (ty::Param(p), _) | (_, ty::Param(p)) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index ce5d3791a48..f1d53cb59cd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -575,12 +575,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     if param_hir.pat.span == param_hir.ty_span {
                         // for `|x|`, `|_|`, `|x: impl Foo|`
                         let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
-                        suggestion += &format!("{}: &_", pat);
+                        suggestion += &format!("{pat}: &_");
                     } else {
                         // for `|x: ty|`, `|_: ty|`
                         let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
                         let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
-                        suggestion += &format!("{}: &{}", pat, ty);
+                        suggestion += &format!("{pat}: &{ty}");
                     }
                     has_suggestion = true;
                 } else {
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 485e34fe2bf..be424424f3a 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -837,9 +837,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             self.var_infos[node_idx].origin.span(),
             format!(
                 "collect_error_for_expanding_node() could not find \
-                 error for var {:?} in universe {:?}, lower_bounds={:#?}, \
-                 upper_bounds={:#?}",
-                node_idx, node_universe, lower_bounds, upper_bounds
+                 error for var {node_idx:?} in universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \
+                 upper_bounds={upper_bounds:#?}"
             ),
         );
     }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 71c07f31bc9..c8049164391 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -557,7 +557,7 @@ where
                 // Forbid inference variables in the RHS.
                 self.infcx.tcx.sess.delay_span_bug(
                     self.delegate.span(),
-                    format!("unexpected inference var {:?}", b,),
+                    format!("unexpected inference var {b:?}",),
                 );
                 Ok(a)
             }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 945136fbff2..9c90b704586 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -619,13 +619,6 @@ impl<'tcx> InferCtxt<'tcx> {
                     {
                         hidden_ty
                     }
-                    // FIXME(RPITIT): This can go away when we move to associated types
-                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
-                    ty::Alias(ty::Projection, ty::AliasTy { def_id: def_id2, args: args2, .. })
-                        if def_id == def_id2 && args == args2 =>
-                    {
-                        hidden_ty
-                    }
                     _ => ty,
                 },
                 lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 0681f414ce9..f36802e1284 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -253,7 +253,7 @@ where
                     // this point it never will be
                     self.tcx.sess.delay_span_bug(
                         origin.span(),
-                        format!("unresolved inference variable in outlives: {:?}", v),
+                        format!("unresolved inference variable in outlives: {v:?}"),
                     );
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 2bc6546ba28..4279d0ab7ab 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -179,7 +179,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                 // this point it never will be
                 self.tcx.sess.delay_span_bug(
                     rustc_span::DUMMY_SP,
-                    format!("unresolved inference variable in outlives: {:?}", v),
+                    format!("unresolved inference variable in outlives: {v:?}"),
                 );
                 // add a bound that never holds
                 VerifyBound::AnyBound(vec![])
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 613da8a0b45..708c51cabeb 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -704,8 +704,8 @@ impl fmt::Debug for RegionSnapshot {
 impl<'tcx> fmt::Debug for GenericKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            GenericKind::Param(ref p) => write!(f, "{:?}", p),
-            GenericKind::Alias(ref p) => write!(f, "{:?}", p),
+            GenericKind::Param(ref p) => write!(f, "{p:?}"),
+            GenericKind::Alias(ref p) => write!(f, "{p:?}"),
         }
     }
 }
@@ -713,8 +713,8 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
 impl<'tcx> fmt::Display for GenericKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            GenericKind::Param(ref p) => write!(f, "{}", p),
-            GenericKind::Alias(ref p) => write!(f, "{}", p),
+            GenericKind::Param(ref p) => write!(f, "{p}"),
+            GenericKind::Alias(ref p) => write!(f, "{p}"),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 9f440f39849..e72a43630e9 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -28,11 +28,11 @@ impl<'tcx> InferCtxt<'tcx> {
         if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
             if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) {
                 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                err.span_label(span, format!("definition of `{}` from trait", item_name));
+                err.span_label(span, format!("definition of `{item_name}` from trait"));
             }
         }
 
-        err.span_label(error_span, format!("impl has extra requirement {}", requirement));
+        err.span_label(error_span, format!("impl has extra requirement {requirement}"));
 
         err
     }
@@ -56,7 +56,7 @@ pub fn report_object_safety_error<'tcx>(
         "the trait `{}` cannot be made into an object",
         trait_str
     );
-    err.span_label(span, format!("`{}` cannot be made into an object", trait_str));
+    err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
 
     let mut reported_violations = FxIndexSet::default();
     let mut multi_span = vec![];
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index e375d611936..afba2e50a23 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -190,7 +190,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
         }
         let fresh_key =
             map.insert(key, ProjectionCacheEntry::NormalizedTy { ty: value, complete: None });
-        assert!(!fresh_key, "never started projecting `{:?}`", key);
+        assert!(!fresh_key, "never started projecting `{key:?}`");
     }
 
     /// Mark the relevant projection cache key as having its derived obligations
@@ -229,7 +229,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
     /// be different).
     pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
         let fresh = self.map().insert(key, ProjectionCacheEntry::Ambiguous);
-        assert!(!fresh, "never started projecting `{:?}`", key);
+        assert!(!fresh, "never started projecting `{key:?}`");
     }
 
     /// Indicates that while trying to normalize `key`, `key` was required to
@@ -237,14 +237,14 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
     /// an error here.
     pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
         let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
-        assert!(!fresh, "never started projecting `{:?}`", key);
+        assert!(!fresh, "never started projecting `{key:?}`");
     }
 
     /// Indicates that trying to normalize `key` resulted in
     /// error.
     pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
         let fresh = self.map().insert(key, ProjectionCacheEntry::Error);
-        assert!(!fresh, "never started projecting `{:?}`", key);
+        assert!(!fresh, "never started projecting `{key:?}`");
     }
 }
 
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 1563d92af0e..8a7c59da09e 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -38,17 +38,17 @@ impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
 impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
-            super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
+            super::CodeSelectionError(ref e) => write!(f, "{e:?}"),
+            super::CodeProjectionError(ref e) => write!(f, "{e:?}"),
             super::CodeSubtypeError(ref a, ref b) => {
-                write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
+                write!(f, "CodeSubtypeError({a:?}, {b:?})")
             }
             super::CodeConstEquateError(ref a, ref b) => {
-                write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
+                write!(f, "CodeConstEquateError({a:?}, {b:?})")
             }
             super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"),
             super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"),
-            super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
+            super::CodeCycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
         }
     }
 }
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 23294dc2e1b..2211ac1c8a7 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -16,7 +16,11 @@ Rust lexer used by rustc. No stability guarantees are provided.
 # Note that this crate purposefully does not depend on other rustc crates
 [dependencies]
 unicode-xid = "0.2.0"
-unic-emoji-char = "0.9.0"
+
+[dependencies.unicode-properties]
+version = "0.1.0"
+default-features = false
+features = ["emoji"]
 
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index d511d2b1280..43dfd34a6ff 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -34,6 +34,7 @@ pub use crate::cursor::Cursor;
 use self::LiteralKind::*;
 use self::TokenKind::*;
 use crate::cursor::EOF_CHAR;
+use unicode_properties::UnicodeEmoji;
 
 /// Parsed token.
 /// It doesn't contain information about data that has been parsed,
@@ -428,9 +429,7 @@ impl Cursor<'_> {
                 Literal { kind, suffix_start }
             }
             // Identifier starting with an emoji. Only lexed for graceful error recovery.
-            c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
-                self.fake_ident_or_unknown_prefix()
-            }
+            c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
             _ => Unknown,
         };
         let res = Token::new(token_kind, self.pos_within_token());
@@ -514,9 +513,7 @@ impl Cursor<'_> {
         // we see a prefix here, it is definitely an unknown prefix.
         match self.first() {
             '#' | '"' | '\'' => UnknownPrefix,
-            c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
-                self.fake_ident_or_unknown_prefix()
-            }
+            c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
             _ => Ident,
         }
     }
@@ -525,7 +522,7 @@ impl Cursor<'_> {
         // Start is already eaten, eat the rest of identifier.
         self.eat_while(|c| {
             unicode_xid::UnicodeXID::is_xid_continue(c)
-                || (!c.is_ascii() && unic_emoji_char::is_emoji(c))
+                || (!c.is_ascii() && c.is_emoji_char())
                 || c == '\u{200d}'
         });
         // Known prefixes must have been handled earlier. So if
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ba05622bf37..e6917f4b2d3 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1458,15 +1458,20 @@ impl TypeAliasBounds {
 
 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else { return };
-        if cx.tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
-            // Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
+        let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return };
+
+        if cx.tcx.features().lazy_type_alias {
+            // Bounds of lazy type aliases are respected.
             return;
         }
-        if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
-            // Bounds are respected for `type X = … Type::Inherent …`
+
+        let ty = cx.tcx.type_of(item.owner_id).skip_binder();
+        if ty.has_opaque_types() || ty.has_inherent_projections() {
+            // Bounds of type aliases that contain opaque types or inherent projections are respected.
+            // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`.
             return;
         }
+
         // There must not be a where clause
         if type_alias_generics.predicates.is_empty() {
             return;
@@ -1491,7 +1496,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
         if !where_spans.is_empty() {
             let sub = (!suggested_changing_assoc_types).then(|| {
                 suggested_changing_assoc_types = true;
-                SuggestChangingAssocTypes { ty }
+                SuggestChangingAssocTypes { ty: hir_ty }
             });
             cx.emit_spanned_lint(
                 TYPE_ALIAS_BOUNDS,
@@ -1507,7 +1512,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
             let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg };
             let sub = (!suggested_changing_assoc_types).then(|| {
                 suggested_changing_assoc_types = true;
-                SuggestChangingAssocTypes { ty }
+                SuggestChangingAssocTypes { ty: hir_ty }
             });
             cx.emit_spanned_lint(
                 TYPE_ALIAS_BOUNDS,
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 53fe0ceb234..84558ee1f02 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -10,6 +10,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
+    /// #![feature(multiple_supertrait_upcastable)]
     /// trait A {}
     /// trait B {}
     ///
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index af6f4d5eaf9..ea045462845 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -92,10 +92,8 @@ enum LLVMRustAttribute {
   NoCfCheck = 35,
   ShadowCallStack = 36,
   AllocSize = 37,
-#if LLVM_VERSION_GE(15, 0)
   AllocatedPointer = 38,
   AllocAlign = 39,
-#endif
   SanitizeSafeStack = 40,
 };
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 71df17c9ce7..ebf8a50ae8b 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -801,9 +801,6 @@ LLVMRustOptimize(
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
           auto CompileKernel = SanitizerOptions->SanitizeKernelAddress;
-#if LLVM_VERSION_LT(15, 0)
-          MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
-#endif
           AddressSanitizerOptions opts = AddressSanitizerOptions{
             CompileKernel,
             SanitizerOptions->SanitizeAddressRecover
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 870a2e02cba..8ef39a6c866 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -277,12 +277,10 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::ShadowCallStack;
   case AllocSize:
     return Attribute::AllocSize;
-#if LLVM_VERSION_GE(15, 0)
   case AllocatedPointer:
     return Attribute::AllocatedPointer;
   case AllocAlign:
     return Attribute::AllocAlign;
-#endif
   case SanitizeSafeStack:
     return Attribute::SafeStack;
   }
@@ -340,20 +338,12 @@ extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, LLVMTy
 }
 
 extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, LLVMTypeRef Ty) {
-#if LLVM_VERSION_GE(15, 0)
   return wrap(Attribute::get(*unwrap(C), Attribute::ElementType, unwrap(Ty)));
-#else
-  report_fatal_error("Should not be needed on LLVM < 15");
-#endif
 }
 
 extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Async) {
-#if LLVM_VERSION_LT(15, 0)
-  return wrap(Attribute::get(*unwrap(C), Attribute::UWTable));
-#else
   return wrap(Attribute::getWithUWTableKind(
       *unwrap(C), Async ? UWTableKind::Async : UWTableKind::Sync));
-#endif
 }
 
 extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
@@ -366,8 +356,6 @@ extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32
                                               ));
 }
 
-#if LLVM_VERSION_GE(15, 0)
-
 // These values **must** match ffi::AllocKindFlags.
 // It _happens_ to match the LLVM values of llvm::AllocFnKind,
 // but that's happenstance and we do explicit conversions before
@@ -411,16 +399,10 @@ static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) {
   }
   return AFK;
 }
-#endif
 
 extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) {
-#if LLVM_VERSION_GE(15, 0)
   return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind,
       static_cast<uint64_t>(allocKindFromRust(static_cast<LLVMRustAllocKindFlags>(AllocKindArg)))));
-#else
-  report_fatal_error(
-      "allockind attributes are new in LLVM 15 and should not be used on older LLVMs");
-#endif
 }
 
 // Simplified representation of `MemoryEffects` across the FFI boundary.
@@ -517,14 +499,9 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
 
 extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
                                         size_t ConstraintsLen) {
-#if LLVM_VERSION_LT(15, 0)
-  return InlineAsm::Verify(unwrap<FunctionType>(Ty),
-                           StringRef(Constraints, ConstraintsLen));
-#else
   // llvm::Error converts to true if it is an error.
   return !llvm::errorToBool(InlineAsm::verify(
       unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen)));
-#endif
 }
 
 typedef DIBuilder *LLVMRustDIBuilderRef;
@@ -1649,19 +1626,11 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *hig
     auto C = unwrap<llvm::ConstantInt>(CV);
     if (C->getBitWidth() > 128) { return false; }
     APInt AP;
-#if LLVM_VERSION_GE(15, 0)
     if (sext) {
         AP = C->getValue().sext(128);
     } else {
         AP = C->getValue().zext(128);
     }
-#else
-    if (sext) {
-        AP = C->getValue().sextOrSelf(128);
-    } else {
-        AP = C->getValue().zextOrSelf(128);
-    }
-#endif
     *low = AP.getLoBits(64).getZExtValue();
     *high = AP.getHiBits(64).getZExtValue();
     return true;
@@ -1923,12 +1892,19 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
           LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {}
 
     virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
-      if (this->LlvmRemarkStreamer) {
-        if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) {
-          if (OptDiagBase->isEnabled()) {
+      // If this diagnostic is one of the optimization remark kinds, we can check if it's enabled
+      // before emitting it. This can avoid many short-lived allocations when unpacking the
+      // diagnostic and converting its various C++ strings into rust strings.
+      // FIXME: some diagnostic infos still allocate before we get here, and avoiding that would be
+      // good in the future. That will require changing a few call sites in LLVM.
+      if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) {
+        if (OptDiagBase->isEnabled()) {
+          if (this->LlvmRemarkStreamer) {
             this->LlvmRemarkStreamer->emit(*OptDiagBase);
             return true;
           }
+        } else {
+          return true;
         }
       }
       if (DiagnosticHandlerCallback) {
@@ -2037,16 +2013,7 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) {
   Mangler().getNameWithPrefix(OS, GV, true);
 }
 
-// LLVMGetAggregateElement was added in LLVM 15. For earlier LLVM versions just
-// use its implementation.
-#if LLVM_VERSION_LT(15, 0)
-extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) {
-    return wrap(unwrap<Constant>(C)->getAggregateElement(Idx));
-}
-#endif
-
 extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
-#if LLVM_VERSION_GE(15, 0)
     auto *CB = unwrap<CallBase>(CallSite);
     switch (CB->getIntrinsicID()) {
         case Intrinsic::arm_ldrex:
@@ -2054,7 +2021,6 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
         case Intrinsic::arm_strex:
             return 1;
     }
-#endif
     return -1;
 }
 
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 3cbb2c21e28..e7b80c64184 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -123,7 +123,7 @@ where
             return Ok(());
         }
         let backtrace = std::backtrace::Backtrace::capture();
-        writeln!(writer, "stack backtrace: \n{:?}", backtrace)
+        writeln!(writer, "stack backtrace: \n{backtrace:?}")
     }
 }
 
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 8d017d149f6..f1e7b8eb6c7 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -43,7 +43,7 @@ fn decodable_body(
     let ty_name = s.ast().ident.to_string();
     let decode_body = match s.variants() {
         [] => {
-            let message = format!("`{}` has no variants to decode", ty_name);
+            let message = format!("`{ty_name}` has no variants to decode");
             quote! {
                 panic!(#message)
             }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 44195996762..fb9dd660d2f 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -908,7 +908,7 @@ pub fn list_file_metadata(
     let flavor = get_flavor_from_path(path);
     match get_metadata_section(target, flavor, path, metadata_loader) {
         Ok(metadata) => metadata.list_crate_metadata(out),
-        Err(msg) => write!(out, "{}\n", msg),
+        Err(msg) => write!(out, "{msg}\n"),
     }
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index a8815ee0908..7dbfe0e0cb0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -246,6 +246,7 @@ provide! { tcx, def_id, other, cdata,
         debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
         cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
     }
+    assumed_wf_types_for_rpitit => { table }
     collect_return_position_impl_trait_in_trait_tys => {
         Ok(cdata
             .root
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8f065dd6b58..d72053ca985 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1144,13 +1144,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
             let assoc_item = tcx.associated_item(def_id);
             match assoc_item.container {
                 ty::AssocItemContainer::ImplContainer => true,
-                // Always encode RPITITs, since we need to be able to project
-                // from an RPITIT associated item to an opaque when installing
-                // the default projection predicates in default trait methods
-                // with RPITITs.
-                ty::AssocItemContainer::TraitContainer => {
-                    assoc_item.defaultness(tcx).has_value() || assoc_item.is_impl_trait_in_trait()
-                }
+                ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(),
             }
         }
         DefKind::TyParam => {
@@ -1560,6 +1554,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
         if let Some(rpitit_info) = item.opt_rpitit_info {
             record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
+            if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
+                record_array!(
+                    self.tables.assumed_wf_types_for_rpitit[def_id]
+                        <- self.tcx.assumed_wf_types_for_rpitit(def_id)
+                );
+            }
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 0bc16fc64ff..a89e235ff28 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -51,7 +51,7 @@ mod encoder;
 mod table;
 
 pub(crate) fn rustc_version(cfg_version: &'static str) -> String {
-    format!("rustc {}", cfg_version)
+    format!("rustc {cfg_version}")
 }
 
 /// Metadata encoding version.
@@ -457,6 +457,7 @@ define_tables! {
     trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
     doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
     doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
+    assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 2dc5b896993..4e242c684e3 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -380,7 +380,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
             let local_id = local_id
                 .as_u64()
                 .try_into()
-                .unwrap_or_else(|_| panic!("local id should be u32, found {:?}", local_id));
+                .unwrap_or_else(|_| panic!("local id should be u32, found {local_id:?}"));
             Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
         } else {
             None
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 0ddbe7d1c29..3ad9b0d79e7 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -35,7 +35,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
                 if let Some(def_id) = node.extract_def_id(tcx) {
                     write!(f, "{}", tcx.def_path_debug_str(def_id))?;
                 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) {
-                    write!(f, "{}", s)?;
+                    write!(f, "{s}")?;
                 } else {
                     write!(f, "{}", node.hash)?;
                 }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index b167364f680..0256e09e4b5 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -534,7 +534,7 @@ impl<'hir> Map<'hir> {
                 (m, span, hir_id)
             }
             Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id),
-            node => panic!("not a module: {:?}", node),
+            node => panic!("not a module: {node:?}"),
         }
     }
 
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 6ce1ad8f43e..9ecc7580f5c 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -218,14 +218,12 @@ pub fn explain_lint_level_source(
             let hyphen_case_lint_name = name.replace('_', "-");
             if lint_flag_val.as_str() == name {
                 err.note_once(format!(
-                    "requested on the command line with `{} {}`",
-                    flag, hyphen_case_lint_name
+                    "requested on the command line with `{flag} {hyphen_case_lint_name}`"
                 ));
             } else {
                 let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
                 err.note_once(format!(
-                    "`{} {}` implied by `{} {}`",
-                    flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
+                    "`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`"
                 ));
             }
         }
@@ -237,8 +235,7 @@ pub fn explain_lint_level_source(
             if lint_attr_name.as_str() != name {
                 let level_str = level.as_str();
                 err.note_once(format!(
-                    "`#[{}({})]` implied by `#[{}({})]`",
-                    level_str, name, level_str, lint_attr_name
+                    "`#[{level_str}({name})]` implied by `#[{level_str}({lint_attr_name})]`"
                 ));
             }
         }
@@ -416,12 +413,11 @@ pub fn struct_lint_level(
                 FutureIncompatibilityReason::EditionError(edition) => {
                     let current_edition = sess.edition();
                     format!(
-                        "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
-                        current_edition, edition
+                        "this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!"
                     )
                 }
                 FutureIncompatibilityReason::EditionSemanticsChange(edition) => {
-                    format!("this changes meaning in Rust {}", edition)
+                    format!("this changes meaning in Rust {edition}")
                 }
                 FutureIncompatibilityReason::Custom(reason) => reason.to_owned(),
             };
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 60844c17e47..908ab8b613e 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -107,7 +107,7 @@ pub fn report_unstable(
     soft_handler: impl FnOnce(&'static Lint, Span, String),
 ) {
     let msg = match reason {
-        Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
+        Some(r) => format!("use of unstable library feature '{feature}': {r}"),
         None => format!("use of unstable library feature '{}'", &feature),
     };
 
@@ -170,7 +170,7 @@ pub fn deprecation_suggestion(
     if let Some(suggestion) = suggestion {
         diag.span_suggestion_verbose(
             span,
-            format!("replace the use of the deprecated {}", kind),
+            format!("replace the use of the deprecated {kind}"),
             suggestion,
             Applicability::MachineApplicable,
         );
@@ -189,12 +189,12 @@ fn deprecation_message(
     path: &str,
 ) -> String {
     let message = if is_in_effect {
-        format!("use of deprecated {} `{}`", kind, path)
+        format!("use of deprecated {kind} `{path}`")
     } else {
         let since = since.as_ref().map(Symbol::as_str);
 
         if since == Some("TBD") {
-            format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path)
+            format!("use of {kind} `{path}` that will be deprecated in a future Rust version")
         } else {
             format!(
                 "use of {} `{}` that will be deprecated in future version {}",
@@ -206,7 +206,7 @@ fn deprecation_message(
     };
 
     match note {
-        Some(reason) => format!("{}: {}", message, reason),
+        Some(reason) => format!("{message}: {reason}"),
         None => message,
     }
 }
@@ -312,7 +312,7 @@ fn suggestion_for_allocator_api(
                     return Some((
                         inner_types,
                         "consider wrapping the inner types in tuple".to_string(),
-                        format!("({})", snippet),
+                        format!("({snippet})"),
                         Applicability::MaybeIncorrect,
                     ));
                 }
@@ -599,7 +599,7 @@ impl<'tcx> TyCtxt<'tcx> {
             |span, def_id| {
                 // The API could be uncallable for other reasons, for example when a private module
                 // was referenced.
-                self.sess.delay_span_bug(span, format!("encountered unmarked API: {:?}", def_id));
+                self.sess.delay_span_bug(span, format!("encountered unmarked API: {def_id:?}"));
             },
         )
     }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index db24dae1130..d7d6e3a0086 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -6,69 +6,43 @@ use rustc_span::Symbol;
 use std::fmt::{self, Debug, Formatter};
 
 rustc_index::newtype_index! {
-    /// An ExpressionOperandId value is assigned directly from either a
-    /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
-    /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
-    /// constant value of `0`.
-    #[derive(HashStable)]
-    #[max = 0xFFFF_FFFF]
-    #[debug_format = "ExpressionOperandId({})"]
-    pub struct ExpressionOperandId {
-    }
-}
-
-impl ExpressionOperandId {
-    /// An expression operand for a "zero counter", as described in the following references:
+    /// ID of a coverage counter. Values ascend from 0.
     ///
-    /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
-    /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
-    /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
-    ///
-    /// This operand can be used to count two or more separate code regions with a single counter,
-    /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
-    /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
-    /// the coverage map for the other code regions.
-    pub const ZERO: Self = Self::from_u32(0);
-}
-
-rustc_index::newtype_index! {
+    /// Note that LLVM handles counter IDs as `uint32_t`, so there is no need
+    /// to use a larger representation on the Rust side.
     #[derive(HashStable)]
     #[max = 0xFFFF_FFFF]
-    #[debug_format = "CounterValueReference({})"]
-    pub struct CounterValueReference {}
+    #[debug_format = "CounterId({})"]
+    pub struct CounterId {}
 }
 
-impl CounterValueReference {
-    /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
-    pub const START: Self = Self::from_u32(1);
+impl CounterId {
+    pub const START: Self = Self::from_u32(0);
 
-    /// Returns explicitly-requested zero-based version of the counter id, used
-    /// during codegen. LLVM expects zero-based indexes.
-    pub fn zero_based_index(self) -> u32 {
-        let one_based_index = self.as_u32();
-        debug_assert!(one_based_index > 0);
-        one_based_index - 1
+    #[inline(always)]
+    pub fn next_id(self) -> Self {
+        Self::from_u32(self.as_u32() + 1)
     }
 }
 
 rustc_index::newtype_index! {
-    /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
+    /// ID of a coverage-counter expression. Values ascend from 0.
     ///
-    /// Values descend from u32::MAX.
+    /// Note that LLVM handles expression IDs as `uint32_t`, so there is no need
+    /// to use a larger representation on the Rust side.
     #[derive(HashStable)]
     #[max = 0xFFFF_FFFF]
-    #[debug_format = "InjectedExpressionId({})"]
-    pub struct InjectedExpressionId {}
+    #[debug_format = "ExpressionId({})"]
+    pub struct ExpressionId {}
 }
 
-rustc_index::newtype_index! {
-    /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
-    ///
-    /// Values ascend from 0.
-    #[derive(HashStable)]
-    #[max = 0xFFFF_FFFF]
-    #[debug_format = "InjectedExpressionIndex({})"]
-    pub struct InjectedExpressionIndex {}
+impl ExpressionId {
+    pub const START: Self = Self::from_u32(0);
+
+    #[inline(always)]
+    pub fn next_id(self) -> Self {
+        Self::from_u32(self.as_u32() + 1)
+    }
 }
 
 rustc_index::newtype_index! {
@@ -81,17 +55,25 @@ rustc_index::newtype_index! {
     pub struct MappedExpressionIndex {}
 }
 
-impl From<CounterValueReference> for ExpressionOperandId {
-    #[inline]
-    fn from(v: CounterValueReference) -> ExpressionOperandId {
-        ExpressionOperandId::from(v.as_u32())
-    }
+/// Operand of a coverage-counter expression.
+///
+/// Operands can be a constant zero value, an actual coverage counter, or another
+/// expression. Counter/expression operands are referred to by ID.
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub enum Operand {
+    Zero,
+    Counter(CounterId),
+    Expression(ExpressionId),
 }
 
-impl From<InjectedExpressionId> for ExpressionOperandId {
-    #[inline]
-    fn from(v: InjectedExpressionId) -> ExpressionOperandId {
-        ExpressionOperandId::from(v.as_u32())
+impl Debug for Operand {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Zero => write!(f, "Zero"),
+            Self::Counter(id) => f.debug_tuple("Counter").field(&id.as_u32()).finish(),
+            Self::Expression(id) => f.debug_tuple("Expression").field(&id.as_u32()).finish(),
+        }
     }
 }
 
@@ -99,23 +81,27 @@ impl From<InjectedExpressionId> for ExpressionOperandId {
 pub enum CoverageKind {
     Counter {
         function_source_hash: u64,
-        id: CounterValueReference,
+        /// ID of this counter within its enclosing function.
+        /// Expressions in the same function can refer to it as an operand.
+        id: CounterId,
     },
     Expression {
-        id: InjectedExpressionId,
-        lhs: ExpressionOperandId,
+        /// ID of this coverage-counter expression within its enclosing function.
+        /// Other expressions in the same function can refer to it as an operand.
+        id: ExpressionId,
+        lhs: Operand,
         op: Op,
-        rhs: ExpressionOperandId,
+        rhs: Operand,
     },
     Unreachable,
 }
 
 impl CoverageKind {
-    pub fn as_operand_id(&self) -> ExpressionOperandId {
+    pub fn as_operand(&self) -> Operand {
         use CoverageKind::*;
         match *self {
-            Counter { id, .. } => ExpressionOperandId::from(id),
-            Expression { id, .. } => ExpressionOperandId::from(id),
+            Counter { id, .. } => Operand::Counter(id),
+            Expression { id, .. } => Operand::Expression(id),
             Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
         }
     }
@@ -132,14 +118,14 @@ impl Debug for CoverageKind {
             Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
             Expression { id, lhs, op, rhs } => write!(
                 fmt,
-                "Expression({:?}) = {} {} {}",
+                "Expression({:?}) = {:?} {} {:?}",
                 id.index(),
-                lhs.index(),
+                lhs,
                 match op {
                     Op::Add => "+",
                     Op::Subtract => "-",
                 },
-                rhs.index(),
+                rhs,
             ),
             Unreachable => write!(fmt, "Unreachable"),
         }
diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs
index d1f3561c02c..d1753427e74 100644
--- a/compiler/rustc_middle/src/mir/generic_graph.rs
+++ b/compiler/rustc_middle/src/mir/generic_graph.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
 pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph {
     let def_id = body.source.def_id();
     let def_name = graphviz_safe_def_name(def_id);
-    let graph_name = format!("Mir_{}", def_name);
+    let graph_name = format!("Mir_{def_name}");
     let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
 
     // Nodes
@@ -48,7 +48,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node
     };
 
     let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() };
-    let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{:?}", x)).collect();
+    let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{x:?}")).collect();
 
     // add the terminator to the stmts, gsgdt can print it out separately
     let mut terminator_head = String::new();
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index ccae7e159b1..299b50525cb 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -70,8 +70,8 @@ impl<
 
         writeln!(w, r#"    graph [{}];"#, graph_attrs.join(" "))?;
         let content_attrs_str = content_attrs.join(" ");
-        writeln!(w, r#"    node [{}];"#, content_attrs_str)?;
-        writeln!(w, r#"    edge [{}];"#, content_attrs_str)?;
+        writeln!(w, r#"    node [{content_attrs_str}];"#)?;
+        writeln!(w, r#"    edge [{content_attrs_str}];"#)?;
 
         // Graph label
         if let Some(graph_label) = &self.graph_label {
@@ -112,7 +112,7 @@ impl<
         //     (format!("{:?}", node), color)
         // };
         let color = if dark_mode { "dimgray" } else { "gray" };
-        let (blk, bgcolor) = (format!("{:?}", node), color);
+        let (blk, bgcolor) = (format!("{node:?}"), color);
         write!(
             w,
             r#"<tr><td bgcolor="{bgcolor}" {attrs} colspan="{colspan}">{blk}</td></tr>"#,
@@ -151,7 +151,7 @@ impl<
             } else {
                 "".to_owned()
             };
-            writeln!(w, r#"    {} -> {} [label=<{}>];"#, src, trg, escaped_edge_label)?;
+            writeln!(w, r#"    {src} -> {trg} [label=<{escaped_edge_label}>];"#)?;
         }
         Ok(())
     }
@@ -163,7 +163,7 @@ impl<
         W: Write,
     {
         let escaped_label = dot::escape_html(label);
-        writeln!(w, r#"    label=<<br/><br/>{}<br align="left"/><br/><br/><br/>>;"#, escaped_label)
+        writeln!(w, r#"    label=<<br/><br/>{escaped_label}<br align="left"/><br/><br/><br/>>;"#)
     }
 
     fn node(&self, node: G::Node) -> String {
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
index 2de73db3a3c..5c7de864430 100644
--- a/compiler/rustc_middle/src/mir/graphviz.rs
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -127,5 +127,5 @@ fn write_graph_label<'tcx, W: std::fmt::Write>(
 }
 
 fn escape<T: Debug>(t: &T) -> String {
-    dot::escape_html(&format!("{:?}", t))
+    dot::escape_html(&format!("{t:?}"))
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
index d4dd56a42c1..2c6bb908f39 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
@@ -542,11 +542,7 @@ impl InitMaskMaterialized {
         debug_assert_eq!(
             result,
             find_bit_slow(self, start, end, is_init),
-            "optimized implementation of find_bit is wrong for start={:?} end={:?} is_init={} init_mask={:#?}",
-            start,
-            end,
-            is_init,
-            self
+            "optimized implementation of find_bit is wrong for start={start:?} end={end:?} is_init={is_init} init_mask={self:#?}"
         );
 
         result
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 6161b16fc46..d44dfa2172a 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -155,7 +155,7 @@ impl<'tcx> InterpErrorInfo<'tcx> {
 }
 
 fn print_backtrace(backtrace: &Backtrace) {
-    eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
+    eprintln!("\n\nAn error occurred in miri:\n{backtrace}");
 }
 
 impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 69c15e9cc06..8b5a8d17301 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -176,7 +176,7 @@ impl<'tcx> GlobalId<'tcx> {
     pub fn display(self, tcx: TyCtxt<'tcx>) -> String {
         let instance_name = with_no_trimmed_paths!(tcx.def_path_str(self.instance.def.def_id()));
         if let Some(promoted) = self.promoted {
-            format!("{}::{:?}", instance_name, promoted)
+            format!("{instance_name}::{promoted:?}")
         } else {
             instance_name
         }
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 47421d0f037..20861d5ffa4 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -135,8 +135,8 @@ static_assert_size!(Scalar, 24);
 impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr),
-            Scalar::Int(int) => write!(f, "{:?}", int),
+            Scalar::Ptr(ptr, _size) => write!(f, "{ptr:?}"),
+            Scalar::Int(int) => write!(f, "{int:?}"),
         }
     }
 }
@@ -144,8 +144,8 @@ impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
 impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
-            Scalar::Int(int) => write!(f, "{}", int),
+            Scalar::Ptr(ptr, _size) => write!(f, "pointer to {ptr:?}"),
+            Scalar::Int(int) => write!(f, "{int}"),
         }
     }
 }
@@ -153,8 +153,8 @@ impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
 impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
-            Scalar::Int(int) => write!(f, "{:#x}", int),
+            Scalar::Ptr(ptr, _size) => write!(f, "pointer to {ptr:?}"),
+            Scalar::Int(int) => write!(f, "{int:#x}"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 3a958548515..c1f87d79b83 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -619,7 +619,7 @@ impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
                 let val = T::decode(d);
                 ClearCrossCrate::Set(val)
             }
-            tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag),
+            tag => panic!("Invalid tag for ClearCrossCrate: {tag:?}"),
         }
     }
 }
@@ -1046,12 +1046,12 @@ pub enum VarDebugInfoContents<'tcx> {
 impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         match self {
-            VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
-            VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
+            VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
+            VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
             VarDebugInfoContents::Composite { ty, fragments } => {
-                write!(fmt, "{:?}{{ ", ty)?;
+                write!(fmt, "{ty:?}{{ ")?;
                 for f in fragments.iter() {
-                    write!(fmt, "{:?}, ", f)?;
+                    write!(fmt, "{f:?}, ")?;
                 }
                 write!(fmt, "}}")
             }
@@ -1315,55 +1315,47 @@ impl<O> AssertKind<O> {
         match self {
             BoundsCheck { ref len, ref index } => write!(
                 f,
-                "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}",
-                len, index
+                "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
             ),
 
             OverflowNeg(op) => {
-                write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op)
+                write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
             }
-            DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op),
+            DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
             RemainderByZero(op) => write!(
                 f,
-                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}",
-                op
+                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
             ),
             Overflow(BinOp::Add, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}",
-                l, r
+                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
             ),
             Overflow(BinOp::Sub, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}",
-                l, r
+                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
             ),
             Overflow(BinOp::Mul, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}",
-                l, r
+                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
             ),
             Overflow(BinOp::Div, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}",
-                l, r
+                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
             ),
             Overflow(BinOp::Rem, l, r) => write!(
                 f,
-                "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}",
-                l, r
+                "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
             ),
             Overflow(BinOp::Shr, _, r) => {
-                write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r)
+                write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {r:?}")
             }
             Overflow(BinOp::Shl, _, r) => {
-                write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r)
+                write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
             }
             MisalignedPointerDereference { required, found } => {
                 write!(
                     f,
-                    "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {:?}, {:?}",
-                    required, found
+                    "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
                 )
             }
             _ => write!(f, "\"{}\"", self.description()),
@@ -1459,9 +1451,9 @@ impl Debug for Statement<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::StatementKind::*;
         match self.kind {
-            Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
+            Assign(box (ref place, ref rv)) => write!(fmt, "{place:?} = {rv:?}"),
             FakeRead(box (ref cause, ref place)) => {
-                write!(fmt, "FakeRead({:?}, {:?})", cause, place)
+                write!(fmt, "FakeRead({cause:?}, {place:?})")
             }
             Retag(ref kind, ref place) => write!(
                 fmt,
@@ -1474,20 +1466,20 @@ impl Debug for Statement<'_> {
                 },
                 place,
             ),
-            StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place),
-            StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place),
+            StorageLive(ref place) => write!(fmt, "StorageLive({place:?})"),
+            StorageDead(ref place) => write!(fmt, "StorageDead({place:?})"),
             SetDiscriminant { ref place, variant_index } => {
-                write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
+                write!(fmt, "discriminant({place:?}) = {variant_index:?}")
             }
-            Deinit(ref place) => write!(fmt, "Deinit({:?})", place),
+            Deinit(ref place) => write!(fmt, "Deinit({place:?})"),
             PlaceMention(ref place) => {
-                write!(fmt, "PlaceMention({:?})", place)
+                write!(fmt, "PlaceMention({place:?})")
             }
             AscribeUserType(box (ref place, ref c_ty), ref variance) => {
-                write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
+                write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
             }
             Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
-                write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
+                write!(fmt, "Coverage::{kind:?} for {rgn:?}")
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
@@ -1767,13 +1759,13 @@ impl Debug for Place<'_> {
         for elem in self.projection.iter() {
             match elem {
                 ProjectionElem::OpaqueCast(ty) => {
-                    write!(fmt, " as {})", ty)?;
+                    write!(fmt, " as {ty})")?;
                 }
                 ProjectionElem::Downcast(Some(name), _index) => {
-                    write!(fmt, " as {})", name)?;
+                    write!(fmt, " as {name})")?;
                 }
                 ProjectionElem::Downcast(None, index) => {
-                    write!(fmt, " as variant#{:?})", index)?;
+                    write!(fmt, " as variant#{index:?})")?;
                 }
                 ProjectionElem::Deref => {
                     write!(fmt, ")")?;
@@ -1782,25 +1774,25 @@ impl Debug for Place<'_> {
                     write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
                 }
                 ProjectionElem::Index(ref index) => {
-                    write!(fmt, "[{:?}]", index)?;
+                    write!(fmt, "[{index:?}]")?;
                 }
                 ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
-                    write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
+                    write!(fmt, "[{offset:?} of {min_length:?}]")?;
                 }
                 ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
-                    write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
+                    write!(fmt, "[-{offset:?} of {min_length:?}]")?;
                 }
                 ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
-                    write!(fmt, "[{:?}:]", from)?;
+                    write!(fmt, "[{from:?}:]")?;
                 }
                 ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
-                    write!(fmt, "[:-{:?}]", to)?;
+                    write!(fmt, "[:-{to:?}]")?;
                 }
                 ProjectionElem::Subslice { from, to, from_end: true } => {
-                    write!(fmt, "[{:?}:-{:?}]", from, to)?;
+                    write!(fmt, "[{from:?}:-{to:?}]")?;
                 }
                 ProjectionElem::Subslice { from, to, from_end: false } => {
-                    write!(fmt, "[{:?}..{:?}]", from, to)?;
+                    write!(fmt, "[{from:?}..{to:?}]")?;
                 }
             }
         }
@@ -1894,9 +1886,9 @@ impl<'tcx> Debug for Operand<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::Operand::*;
         match *self {
-            Constant(ref a) => write!(fmt, "{:?}", a),
-            Copy(ref place) => write!(fmt, "{:?}", place),
-            Move(ref place) => write!(fmt, "move {:?}", place),
+            Constant(ref a) => write!(fmt, "{a:?}"),
+            Copy(ref place) => write!(fmt, "{place:?}"),
+            Move(ref place) => write!(fmt, "move {place:?}"),
         }
     }
 }
@@ -1935,11 +1927,11 @@ impl<'tcx> Operand<'tcx> {
             let param_env_and_ty = ty::ParamEnv::empty().and(ty);
             let type_size = tcx
                 .layout_of(param_env_and_ty)
-                .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+                .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
                 .size;
             let scalar_size = match val {
                 Scalar::Int(int) => int.size(),
-                _ => panic!("Invalid scalar type {:?}", val),
+                _ => panic!("Invalid scalar type {val:?}"),
             };
             scalar_size == type_size
         });
@@ -2055,26 +2047,26 @@ impl<'tcx> Debug for Rvalue<'tcx> {
         use self::Rvalue::*;
 
         match *self {
-            Use(ref place) => write!(fmt, "{:?}", place),
+            Use(ref place) => write!(fmt, "{place:?}"),
             Repeat(ref a, b) => {
-                write!(fmt, "[{:?}; ", a)?;
+                write!(fmt, "[{a:?}; ")?;
                 pretty_print_const(b, fmt, false)?;
                 write!(fmt, "]")
             }
-            Len(ref a) => write!(fmt, "Len({:?})", a),
+            Len(ref a) => write!(fmt, "Len({a:?})"),
             Cast(ref kind, ref place, ref ty) => {
-                write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind)
+                write!(fmt, "{place:?} as {ty:?} ({kind:?})")
             }
-            BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
+            BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
             CheckedBinaryOp(ref op, box (ref a, ref b)) => {
-                write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b)
+                write!(fmt, "Checked{op:?}({a:?}, {b:?})")
             }
-            UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
-            Discriminant(ref place) => write!(fmt, "discriminant({:?})", place),
+            UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
+            Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
             NullaryOp(ref op, ref t) => match op {
-                NullOp::SizeOf => write!(fmt, "SizeOf({:?})", t),
-                NullOp::AlignOf => write!(fmt, "AlignOf({:?})", t),
-                NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({:?}, {:?})", t, fields),
+                NullOp::SizeOf => write!(fmt, "SizeOf({t:?})"),
+                NullOp::AlignOf => write!(fmt, "AlignOf({t:?})"),
+                NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t:?}, {fields:?})"),
             },
             ThreadLocalRef(did) => ty::tls::with(|tcx| {
                 let muta = tcx.static_mutability(did).unwrap().prefix_str();
@@ -2101,10 +2093,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                     // Do not even print 'static
                     String::new()
                 };
-                write!(fmt, "&{}{}{:?}", region, kind_str, place)
+                write!(fmt, "&{region}{kind_str}{place:?}")
             }
 
-            CopyForDeref(ref place) => write!(fmt, "deref_copy {:#?}", place),
+            CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"),
 
             AddressOf(mutability, ref place) => {
                 let kind_str = match mutability {
@@ -2112,7 +2104,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                     Mutability::Not => "const",
                 };
 
-                write!(fmt, "&raw {} {:?}", kind_str, place)
+                write!(fmt, "&raw {kind_str} {place:?}")
             }
 
             Aggregate(ref kind, ref places) => {
@@ -2125,7 +2117,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 };
 
                 match **kind {
-                    AggregateKind::Array(_) => write!(fmt, "{:?}", places),
+                    AggregateKind::Array(_) => write!(fmt, "{places:?}"),
 
                     AggregateKind::Tuple => {
                         if places.is_empty() {
@@ -2211,7 +2203,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
 
             ShallowInitBox(ref place, ref ty) => {
-                write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty)
+                write!(fmt, "ShallowInitBox({place:?}, {ty:?})")
             }
         }
     }
@@ -2755,7 +2747,7 @@ rustc_index::newtype_index! {
 
 impl<'tcx> Debug for Constant<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{}", self)
+        write!(fmt, "{self}")
     }
 }
 
@@ -2831,7 +2823,7 @@ fn pretty_print_const_value<'tcx>(
         let ty = tcx.lift(ty).unwrap();
 
         if tcx.sess.verbose() {
-            fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?;
+            fmt.write_str(&format!("ConstValue({ct:?}: {ty})"))?;
             return Ok(());
         }
 
@@ -2901,7 +2893,7 @@ fn pretty_print_const_value<'tcx>(
                             fmt.write_str(")")?;
                         }
                         ty::Adt(def, _) if def.variants().is_empty() => {
-                            fmt.write_str(&format!("{{unreachable(): {}}}", ty))?;
+                            fmt.write_str(&format!("{{unreachable(): {ty}}}"))?;
                         }
                         ty::Adt(def, args) => {
                             let variant_idx = contents
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index f4133dfbc95..ddb6cc15bc1 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -223,7 +223,7 @@ impl<'tcx> MonoItem<'tcx> {
 impl<'tcx> fmt::Display for MonoItem<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            MonoItem::Fn(instance) => write!(f, "fn {}", instance),
+            MonoItem::Fn(instance) => write!(f, "fn {instance}"),
             MonoItem::Static(def_id) => {
                 write!(f, "static {}", Instance::new(def_id, GenericArgs::empty()))
             }
@@ -534,17 +534,17 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
             format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id, local_crate_id)
         });
 
-        write!(cgu_name, "{}", crate_prefix).unwrap();
+        write!(cgu_name, "{crate_prefix}").unwrap();
 
         // Add the components
         for component in components {
-            write!(cgu_name, "-{}", component).unwrap();
+            write!(cgu_name, "-{component}").unwrap();
         }
 
         if let Some(special_suffix) = special_suffix {
             // We add a dot in here so it cannot clash with anything in a regular
             // Rust identifier
-            write!(cgu_name, ".{}", special_suffix).unwrap();
+            write!(cgu_name, ".{special_suffix}").unwrap();
         }
 
         Symbol::intern(&cgu_name)
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 8cbab31451b..27e39137092 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -124,14 +124,14 @@ fn dump_matched_mir_node<'tcx, F>(
         let def_path =
             ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
         // ignore-tidy-odd-backticks the literal below is fine
-        write!(file, "// MIR for `{}", def_path)?;
+        write!(file, "// MIR for `{def_path}")?;
         match body.source.promoted {
             None => write!(file, "`")?,
-            Some(promoted) => write!(file, "::{:?}`", promoted)?,
+            Some(promoted) => write!(file, "::{promoted:?}`")?,
         }
-        writeln!(file, " {} {}", disambiguator, pass_name)?;
+        writeln!(file, " {disambiguator} {pass_name}")?;
         if let Some(ref layout) = body.generator_layout() {
-            writeln!(file, "/* generator_layout = {:#?} */", layout)?;
+            writeln!(file, "/* generator_layout = {layout:#?} */")?;
         }
         writeln!(file)?;
         extra_data(PassWhere::BeforeCFG, &mut file)?;
@@ -169,7 +169,7 @@ fn dump_file_basename<'tcx>(
 ) -> String {
     let source = body.source;
     let promotion_id = match source.promoted {
-        Some(id) => format!("-{:?}", id),
+        Some(id) => format!("-{id:?}"),
         None => String::new(),
     };
 
@@ -203,8 +203,7 @@ fn dump_file_basename<'tcx>(
     };
 
     format!(
-        "{}.{}{}{}{}.{}.{}",
-        crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator,
+        "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}",
     )
 }
 
@@ -215,7 +214,7 @@ fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
     let mut file_path = PathBuf::new();
     file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir));
 
-    let file_name = format!("{}.{}", basename, extension,);
+    let file_name = format!("{basename}.{extension}",);
 
     file_path.push(&file_name);
 
@@ -233,12 +232,12 @@ fn create_dump_file_with_basename(
         fs::create_dir_all(parent).map_err(|e| {
             io::Error::new(
                 e.kind(),
-                format!("IO error creating MIR dump directory: {:?}; {}", parent, e),
+                format!("IO error creating MIR dump directory: {parent:?}; {e}"),
             )
         })?;
     }
     Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
-        io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e))
+        io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
     })?))
 }
 
@@ -346,28 +345,24 @@ where
 
     // Basic block label at the top.
     let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" };
-    writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?;
+    writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?;
 
     // List of statements in the middle.
     let mut current_location = Location { block, statement_index: 0 };
     for statement in &data.statements {
         extra_data(PassWhere::BeforeLocation(current_location), w)?;
-        let indented_body = format!("{0}{0}{1:?};", INDENT, statement);
+        let indented_body = format!("{INDENT}{INDENT}{statement:?};");
         if tcx.sess.opts.unstable_opts.mir_include_spans {
             writeln!(
                 w,
                 "{:A$} // {}{}",
                 indented_body,
-                if tcx.sess.verbose() {
-                    format!("{:?}: ", current_location)
-                } else {
-                    String::new()
-                },
+                if tcx.sess.verbose() { format!("{current_location:?}: ") } else { String::new() },
                 comment(tcx, statement.source_info),
                 A = ALIGN,
             )?;
         } else {
-            writeln!(w, "{}", indented_body)?;
+            writeln!(w, "{indented_body}")?;
         }
 
         write_extra(tcx, w, |visitor| {
@@ -387,12 +382,12 @@ where
             w,
             "{:A$} // {}{}",
             indented_terminator,
-            if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() },
+            if tcx.sess.verbose() { format!("{current_location:?}: ") } else { String::new() },
             comment(tcx, data.terminator().source_info),
             A = ALIGN,
         )?;
     } else {
-        writeln!(w, "{}", indented_terminator)?;
+        writeln!(w, "{indented_terminator}")?;
     }
 
     write_extra(tcx, w, |visitor| {
@@ -402,7 +397,7 @@ where
     extra_data(PassWhere::AfterLocation(current_location), w)?;
     extra_data(PassWhere::AfterTerminator(block), w)?;
 
-    writeln!(w, "{}}}", INDENT)
+    writeln!(w, "{INDENT}}}")
 }
 
 /// After we print the main statement, we sometimes dump extra
@@ -457,25 +452,25 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                 self.tcx.sess.source_map().span_to_embeddable_string(*span)
             ));
             if let Some(user_ty) = user_ty {
-                self.push(&format!("+ user_ty: {:?}", user_ty));
+                self.push(&format!("+ user_ty: {user_ty:?}"));
             }
 
             // FIXME: this is a poor version of `pretty_print_const_value`.
             let fmt_val = |val: &ConstValue<'tcx>| match val {
                 ConstValue::ZeroSized => "<ZST>".to_string(),
-                ConstValue::Scalar(s) => format!("Scalar({:?})", s),
+                ConstValue::Scalar(s) => format!("Scalar({s:?})"),
                 ConstValue::Slice { .. } => "Slice(..)".to_string(),
                 ConstValue::ByRef { .. } => "ByRef(..)".to_string(),
             };
 
             let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
-                ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
+                ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({leaf:?})"),
                 ty::ValTree::Branch(_) => "ValTree::Branch(..)".to_string(),
             };
 
             let val = match literal {
                 ConstantKind::Ty(ct) => match ct.kind() {
-                    ty::ConstKind::Param(p) => format!("Param({})", p),
+                    ty::ConstKind::Param(p) => format!("Param({p})"),
                     ty::ConstKind::Unevaluated(uv) => {
                         format!("Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
                     }
@@ -514,20 +509,20 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
             match **kind {
                 AggregateKind::Closure(def_id, args) => {
                     self.push("closure");
-                    self.push(&format!("+ def_id: {:?}", def_id));
-                    self.push(&format!("+ args: {:#?}", args));
+                    self.push(&format!("+ def_id: {def_id:?}"));
+                    self.push(&format!("+ args: {args:#?}"));
                 }
 
                 AggregateKind::Generator(def_id, args, movability) => {
                     self.push("generator");
-                    self.push(&format!("+ def_id: {:?}", def_id));
-                    self.push(&format!("+ args: {:#?}", args));
-                    self.push(&format!("+ movability: {:?}", movability));
+                    self.push(&format!("+ def_id: {def_id:?}"));
+                    self.push(&format!("+ args: {args:#?}"));
+                    self.push(&format!("+ movability: {movability:?}"));
                 }
 
                 AggregateKind::Adt(_, _, _, Some(user_ty), _) => {
                     self.push("adt");
-                    self.push(&format!("+ user_ty: {:?}", user_ty));
+                    self.push(&format!("+ user_ty: {user_ty:?}"));
                 }
 
                 _ => {}
@@ -578,7 +573,7 @@ fn write_scope_tree(
                 comment(tcx, var_debug_info.source_info),
             )?;
         } else {
-            writeln!(w, "{}", indented_debug_info)?;
+            writeln!(w, "{indented_debug_info}")?;
         }
     }
 
@@ -600,7 +595,7 @@ fn write_scope_tree(
             format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
         if let Some(user_ty) = &local_decl.user_ty {
             for user_ty in user_ty.projections() {
-                write!(indented_decl, " as {:?}", user_ty).unwrap();
+                write!(indented_decl, " as {user_ty:?}").unwrap();
             }
         }
         indented_decl.push(';');
@@ -617,7 +612,7 @@ fn write_scope_tree(
                 comment(tcx, local_decl.source_info),
             )?;
         } else {
-            writeln!(w, "{}", indented_decl,)?;
+            writeln!(w, "{indented_decl}",)?;
         }
     }
 
@@ -654,10 +649,10 @@ fn write_scope_tree(
                     tcx.sess.source_map().span_to_embeddable_string(span),
                 )?;
             } else {
-                writeln!(w, "{}", indented_header)?;
+                writeln!(w, "{indented_header}")?;
             }
         } else {
-            writeln!(w, "{}", indented_header)?;
+            writeln!(w, "{indented_header}")?;
         }
 
         write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?;
@@ -844,7 +839,7 @@ fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fm
     for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) {
         write!(w, "   ")?;
     }
-    writeln!(w, " │ {}", ascii)
+    writeln!(w, " │ {ascii}")
 }
 
 /// Number of bytes to print per allocation hex dump line.
@@ -880,7 +875,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
     if num_lines > 0 {
         write!(w, "{}0x{:02$x} │ ", prefix, 0, pos_width)?;
     } else {
-        write!(w, "{}", prefix)?;
+        write!(w, "{prefix}")?;
     }
 
     let mut i = Size::ZERO;
@@ -913,10 +908,10 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
             let offset = Size::from_bytes(offset);
             let provenance_width = |bytes| bytes * 3;
             let ptr = Pointer::new(prov, offset);
-            let mut target = format!("{:?}", ptr);
+            let mut target = format!("{ptr:?}");
             if target.len() > provenance_width(ptr_size.bytes_usize() - 1) {
                 // This is too long, try to save some space.
-                target = format!("{:#?}", ptr);
+                target = format!("{ptr:#?}");
             }
             if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE {
                 // This branch handles the situation where a provenance starts in the current line
@@ -935,10 +930,10 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
                     line_start =
                         write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
                     ascii.clear();
-                    write!(w, "{0:─^1$}╼", target, overflow_width)?;
+                    write!(w, "{target:─^overflow_width$}╼")?;
                 } else {
                     oversized_ptr(&mut target, remainder_width);
-                    write!(w, "╾{0:─^1$}", target, remainder_width)?;
+                    write!(w, "╾{target:─^remainder_width$}")?;
                     line_start =
                         write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
                     write!(w, "{0:─^1$}╼", "", overflow_width)?;
@@ -955,7 +950,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
                 let provenance_width = provenance_width(ptr_size.bytes_usize() - 1);
                 oversized_ptr(&mut target, provenance_width);
                 ascii.push('╾');
-                write!(w, "╾{0:─^1$}╼", target, provenance_width)?;
+                write!(w, "╾{target:─^provenance_width$}╼")?;
                 for _ in 0..ptr_size.bytes() - 2 {
                     ascii.push('─');
                 }
@@ -972,7 +967,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
             // Format is similar to "oversized" above.
             let j = i.bytes_usize();
             let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
-            write!(w, "╾{:02x}{:#?} (1 ptr byte)╼", c, prov)?;
+            write!(w, "╾{c:02x}{prov:#?} (1 ptr byte)╼")?;
             i += Size::from_bytes(1);
         } else if alloc
             .init_mask()
@@ -984,7 +979,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
             // Checked definedness (and thus range) and provenance. This access also doesn't
             // influence interpreter execution but is only for debugging.
             let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
-            write!(w, "{:02x}", c)?;
+            write!(w, "{c:02x}")?;
             if c.is_ascii_control() || c >= 0x80 {
                 ascii.push('.');
             } else {
@@ -1018,7 +1013,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
         _ => tcx.is_closure(def_id),
     };
     match (kind, body.source.promoted) {
-        (_, Some(i)) => write!(w, "{:?} in ", i)?,
+        (_, Some(i)) => write!(w, "{i:?} in ")?,
         (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
         (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
         (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
@@ -1051,7 +1046,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
 
     if let Some(yield_ty) = body.yield_ty() {
         writeln!(w)?;
-        writeln!(w, "yields {}", yield_ty)?;
+        writeln!(w, "yields {yield_ty}")?;
     }
 
     write!(w, " ")?;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index e8cb9860ee5..71bec49af93 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -198,7 +198,7 @@ impl Debug for GeneratorLayout<'_> {
                 if fmt.alternate() {
                     write!(fmt, "{:9}({:?})", variant_name, self.0)
                 } else {
-                    write!(fmt, "{}", variant_name)
+                    write!(fmt, "{variant_name}")
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 730c551576a..20a9e6889e4 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -159,10 +159,10 @@ where
         indent_to_initial_start_col,
         source_map.span_to_snippet(spanview_span).expect("function should have printable source")
     );
-    writeln!(w, "{}", HEADER)?;
-    writeln!(w, "<title>{}</title>", title)?;
-    writeln!(w, "{}", STYLE_SECTION)?;
-    writeln!(w, "{}", START_BODY)?;
+    writeln!(w, "{HEADER}")?;
+    writeln!(w, "<title>{title}</title>")?;
+    writeln!(w, "{STYLE_SECTION}")?;
+    writeln!(w, "{START_BODY}")?;
     write!(
         w,
         r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
@@ -226,7 +226,7 @@ where
         write_coverage_gap(tcx, from_pos, end_pos, w)?;
     }
     writeln!(w, r#"</span></div>"#)?;
-    writeln!(w, "{}", FOOTER)?;
+    writeln!(w, "{FOOTER}")?;
     Ok(())
 }
 
@@ -561,17 +561,16 @@ where
     }
     for (i, line) in html_snippet.lines().enumerate() {
         if i > 0 {
-            write!(w, "{}", NEW_LINE_SPAN)?;
+            write!(w, "{NEW_LINE_SPAN}")?;
         }
         write!(
             w,
-            r#"<span class="code{}" style="--layer: {}"{}>{}</span>"#,
-            maybe_alt_class, layer, maybe_title_attr, line
+            r#"<span class="code{maybe_alt_class}" style="--layer: {layer}"{maybe_title_attr}>{line}</span>"#
         )?;
     }
     // Check for and translate trailing newlines, because `str::lines()` ignores them
     if html_snippet.ends_with('\n') {
-        write!(w, "{}", NEW_LINE_SPAN)?;
+        write!(w, "{NEW_LINE_SPAN}")?;
     }
     if layer == 1 {
         write!(w, "</span>")?;
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 1b9c1438f40..6de84351595 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -280,7 +280,7 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
 
         match (successor_count, unwind) {
             (0, None) => Ok(()),
-            (0, Some(unwind)) => write!(fmt, " -> {}", unwind),
+            (0, Some(unwind)) => write!(fmt, " -> {unwind}"),
             (1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
             _ => {
                 write!(fmt, " -> [")?;
@@ -307,22 +307,22 @@ impl<'tcx> TerminatorKind<'tcx> {
         use self::TerminatorKind::*;
         match self {
             Goto { .. } => write!(fmt, "goto"),
-            SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr),
+            SwitchInt { discr, .. } => write!(fmt, "switchInt({discr:?})"),
             Return => write!(fmt, "return"),
             GeneratorDrop => write!(fmt, "generator_drop"),
             Resume => write!(fmt, "resume"),
             Terminate => write!(fmt, "abort"),
-            Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
+            Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
             Unreachable => write!(fmt, "unreachable"),
-            Drop { place, .. } => write!(fmt, "drop({:?})", place),
+            Drop { place, .. } => write!(fmt, "drop({place:?})"),
             Call { func, args, destination, .. } => {
-                write!(fmt, "{:?} = ", destination)?;
-                write!(fmt, "{:?}(", func)?;
+                write!(fmt, "{destination:?} = ")?;
+                write!(fmt, "{func:?}(")?;
                 for (index, arg) in args.iter().enumerate() {
                     if index > 0 {
                         write!(fmt, ", ")?;
                     }
-                    write!(fmt, "{:?}", arg)?;
+                    write!(fmt, "{arg:?}")?;
                 }
                 write!(fmt, ")")
             }
@@ -331,7 +331,7 @@ impl<'tcx> TerminatorKind<'tcx> {
                 if !expected {
                     write!(fmt, "!")?;
                 }
-                write!(fmt, "{:?}, ", cond)?;
+                write!(fmt, "{cond:?}, ")?;
                 msg.fmt_assert_args(fmt)?;
                 write!(fmt, ")")
             }
@@ -344,7 +344,7 @@ impl<'tcx> TerminatorKind<'tcx> {
                     let print_late = |&late| if late { "late" } else { "" };
                     match op {
                         InlineAsmOperand::In { reg, value } => {
-                            write!(fmt, "in({}) {:?}", reg, value)?;
+                            write!(fmt, "in({reg}) {value:?}")?;
                         }
                         InlineAsmOperand::Out { reg, late, place: Some(place) } => {
                             write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
@@ -371,17 +371,17 @@ impl<'tcx> TerminatorKind<'tcx> {
                             write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
                         }
                         InlineAsmOperand::Const { value } => {
-                            write!(fmt, "const {:?}", value)?;
+                            write!(fmt, "const {value:?}")?;
                         }
                         InlineAsmOperand::SymFn { value } => {
-                            write!(fmt, "sym_fn {:?}", value)?;
+                            write!(fmt, "sym_fn {value:?}")?;
                         }
                         InlineAsmOperand::SymStatic { def_id } => {
-                            write!(fmt, "sym_static {:?}", def_id)?;
+                            write!(fmt, "sym_static {def_id:?}")?;
                         }
                     }
                 }
-                write!(fmt, ", options({:?}))", options)
+                write!(fmt, ", options({options:?}))")
             }
         }
     }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index fb796587352..63df2830e0a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -885,6 +885,13 @@ rustc_queries! {
         desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
     }
 
+    /// We need to store the assumed_wf_types for an RPITIT so that impls of foreign
+    /// traits with return-position impl trait in traits can inherit the right wf types.
+    query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] {
+        desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
+    }
+
     /// Computes the signature of the function.
     query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
@@ -1277,7 +1284,7 @@ rustc_queries! {
     query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
         desc { |tcx| "vtable const allocation for <{} as {}>",
             key.0,
-            key.1.map(|trait_ref| format!("{}", trait_ref)).unwrap_or("_".to_owned())
+            key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned())
         }
     }
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index e070b054720..8e2e71fd879 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -659,7 +659,7 @@ impl<'tcx> Pat<'tcx> {
 
 impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        format!("{}", self).into_diagnostic_arg()
+        format!("{self}").into_diagnostic_arg()
     }
 }
 
@@ -789,7 +789,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
 
         match self.kind {
             PatKind::Wild => write!(f, "_"),
-            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
+            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
             PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
                 let is_mut = match mode {
                     BindingMode::ByValue => mutability == Mutability::Mut,
@@ -801,9 +801,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 if is_mut {
                     write!(f, "mut ")?;
                 }
-                write!(f, "{}", name)?;
+                write!(f, "{name}")?;
                 if let Some(ref subpattern) = *subpattern {
-                    write!(f, " @ {}", subpattern)?;
+                    write!(f, " @ {subpattern}")?;
                 }
                 Ok(())
             }
@@ -833,7 +833,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 };
 
                 if let Some((variant, name)) = &variant_and_name {
-                    write!(f, "{}", name)?;
+                    write!(f, "{name}")?;
 
                     // Only for Adt we can have `S {...}`,
                     // which we handle separately here.
@@ -893,13 +893,13 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                     }
                     _ => bug!("{} is a bad Deref pattern type", self.ty),
                 }
-                write!(f, "{}", subpattern)
+                write!(f, "{subpattern}")
             }
-            PatKind::Constant { value } => write!(f, "{}", value),
+            PatKind::Constant { value } => write!(f, "{value}"),
             PatKind::Range(box PatRange { lo, hi, end }) => {
-                write!(f, "{}", lo)?;
-                write!(f, "{}", end)?;
-                write!(f, "{}", hi)
+                write!(f, "{lo}")?;
+                write!(f, "{end}")?;
+                write!(f, "{hi}")
             }
             PatKind::Slice { ref prefix, ref slice, ref suffix }
             | PatKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -911,7 +911,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                     write!(f, "{}", start_or_comma())?;
                     match slice.kind {
                         PatKind::Wild => {}
-                        _ => write!(f, "{}", slice)?,
+                        _ => write!(f, "{slice}")?,
                     }
                     write!(f, "..")?;
                 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a2b33bb2737..85116555fc0 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -777,49 +777,48 @@ impl ObjectSafetyViolation {
                 "where clause cannot reference non-lifetime `for<...>` variables".into()
             }
             ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
-                format!("associated function `{}` has no `self` parameter", name).into()
+                format!("associated function `{name}` has no `self` parameter").into()
             }
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::ReferencesSelfInput(_),
                 DUMMY_SP,
-            ) => format!("method `{}` references the `Self` type in its parameters", name).into(),
+            ) => format!("method `{name}` references the `Self` type in its parameters").into(),
             ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
-                format!("method `{}` references the `Self` type in this parameter", name).into()
+                format!("method `{name}` references the `Self` type in this parameter").into()
             }
             ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
-                format!("method `{}` references the `Self` type in its return type", name).into()
+                format!("method `{name}` references the `Self` type in its return type").into()
             }
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::ReferencesImplTraitInTrait(_),
                 _,
-            ) => format!("method `{}` references an `impl Trait` type in its return type", name)
-                .into(),
+            ) => {
+                format!("method `{name}` references an `impl Trait` type in its return type").into()
+            }
             ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
-                format!("method `{}` is `async`", name).into()
+                format!("method `{name}` is `async`").into()
             }
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::WhereClauseReferencesSelf,
                 _,
-            ) => {
-                format!("method `{}` references the `Self` type in its `where` clause", name).into()
-            }
+            ) => format!("method `{name}` references the `Self` type in its `where` clause").into(),
             ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
-                format!("method `{}` has generic type parameters", name).into()
+                format!("method `{name}` has generic type parameters").into()
             }
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::UndispatchableReceiver(_),
                 _,
-            ) => format!("method `{}`'s `self` parameter cannot be dispatched on", name).into(),
+            ) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(),
             ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
-                format!("it contains associated `const` `{}`", name).into()
+                format!("it contains associated `const` `{name}`").into()
             }
             ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
             ObjectSafetyViolation::GAT(name, _) => {
-                format!("it contains the generic associated type `{}`", name).into()
+                format!("it contains the generic associated type `{name}`").into()
             }
         }
     }
@@ -837,8 +836,7 @@ impl ObjectSafetyViolation {
                 err.span_suggestion(
                     add_self_sugg.1,
                     format!(
-                        "consider turning `{}` into a method by giving it a `&self` argument",
-                        name
+                        "consider turning `{name}` into a method by giving it a `&self` argument"
                     ),
                     add_self_sugg.0.to_string(),
                     Applicability::MaybeIncorrect,
@@ -846,9 +844,8 @@ impl ObjectSafetyViolation {
                 err.span_suggestion(
                     make_sized_sugg.1,
                     format!(
-                        "alternatively, consider constraining `{}` so it does not apply to \
-                             trait objects",
-                        name
+                        "alternatively, consider constraining `{name}` so it does not apply to \
+                             trait objects"
                     ),
                     make_sized_sugg.0.to_string(),
                     Applicability::MaybeIncorrect,
@@ -861,7 +858,7 @@ impl ObjectSafetyViolation {
             ) => {
                 err.span_suggestion(
                     *span,
-                    format!("consider changing method `{}`'s `self` parameter to be `&self`", name),
+                    format!("consider changing method `{name}`'s `self` parameter to be `&self`"),
                     "&Self",
                     Applicability::MachineApplicable,
                 );
@@ -869,7 +866,7 @@ impl ObjectSafetyViolation {
             ObjectSafetyViolation::AssocConst(name, _)
             | ObjectSafetyViolation::GAT(name, _)
             | ObjectSafetyViolation::Method(name, ..) => {
-                err.help(format!("consider moving `{}` to another trait", name));
+                err.help(format!("consider moving `{name}` to another trait"));
             }
         }
     }
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 73b332fd8ec..b21a00e4122 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -57,6 +57,7 @@ pub enum Certainty {
 
 impl Certainty {
     pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
+    pub const OVERFLOW: Certainty = Certainty::Maybe(MaybeCause::Overflow);
 
     /// Use this function to merge the certainty of multiple nested subgoals.
     ///
@@ -66,7 +67,7 @@ impl Certainty {
     /// success, we merge these two responses. This results in ambiguity.
     ///
     /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
-    /// inside of the solver as we distinguish ambiguity from overflow. It does
+    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
     /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
     /// in ambiguity without changing the inference state, we still want to tell the
     /// user that `T: Baz` results in overflow.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 39f84279259..f1e567e9bf8 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -68,7 +68,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
             writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
             self.nested(|this| {
                 for goal in goal.returned_goals.iter() {
-                    writeln!(this.f, "ADDED GOAL: {:?},", goal)?;
+                    writeln!(this.f, "ADDED GOAL: {goal:?},")?;
                 }
                 Ok(())
             })?;
@@ -104,7 +104,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
                 writeln!(self.f, "ASSEMBLING CANDIDATES FOR DYN UPCASTING:")
             }
             CandidateKind::Candidate { name, result } => {
-                writeln!(self.f, "CANDIDATE {}: {:?}", name, result)
+                writeln!(self.f, "CANDIDATE {name}: {result:?}")
             }
         }?;
 
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 18a57b6181a..e48b46d12c4 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -43,7 +43,7 @@ impl Graph {
     /// The parent of a given impl, which is the `DefId` of the trait when the
     /// impl is a "specialization root".
     pub fn parent(&self, child: DefId) -> DefId {
-        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
+        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {child:?}"))
     }
 }
 
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 530d1ec5d35..d7dc429f53b 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -7,14 +7,14 @@ use std::fmt;
 impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            super::ImplSource::UserDefined(v) => write!(f, "{:?}", v),
+            super::ImplSource::UserDefined(v) => write!(f, "{v:?}"),
 
             super::ImplSource::Builtin(source, d) => {
                 write!(f, "Builtin({source:?}, {d:?})")
             }
 
             super::ImplSource::Param(ct, n) => {
-                write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
+                write!(f, "ImplSourceParamData({n:?}, {ct:?})")
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 91eefa2c125..42f22604975 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -348,7 +348,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
     for (i, proj) in place.projections.iter().enumerate() {
         match proj.kind {
             HirProjectionKind::Deref => {
-                curr_string = format!("*{}", curr_string);
+                curr_string = format!("*{curr_string}");
             }
             HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
                 ty::Adt(def, ..) => {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 4ef70107f19..cce10417e1b 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -212,7 +212,7 @@ impl<'tcx> Const<'tcx> {
                 Err(e) => {
                     tcx.sess.delay_span_bug(
                         expr.span,
-                        format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+                        format!("Const::from_anon_const: couldn't lit_to_const {e:?}"),
                     );
                 }
             }
@@ -267,7 +267,7 @@ impl<'tcx> Const<'tcx> {
     pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
         let size = tcx
             .layout_of(ty)
-            .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+            .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
             .size;
         ty::Const::new_value(
             tcx,
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 624195cfb28..b16163edf14 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -463,7 +463,7 @@ impl TryFrom<ScalarInt> for Double {
 impl fmt::Debug for ScalarInt {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Dispatch to LowerHex below.
-        write!(f, "0x{:x}", self)
+        write!(f, "0x{self:x}")
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 6c76075c214..db4a15fbee5 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -17,7 +17,7 @@ pub struct UnevaluatedConst<'tcx> {
 
 impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> {
     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
-        format!("{:?}", self).into_diagnostic_arg()
+        format!("{self:?}").into_diagnostic_arg()
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 905e855896e..8570f83dcc6 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -126,7 +126,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
         if constraint.ends_with('>') {
             constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term);
         } else {
-            constraint.push_str(&format!("<{} = {}>", name, term));
+            constraint.push_str(&format!("<{name} = {term}>"));
         }
     }
 
@@ -274,9 +274,9 @@ pub fn suggest_constraining_type_params<'a>(
                 if span_to_replace.is_some() {
                     constraint.clone()
                 } else if bound_list_non_empty {
-                    format!(" + {}", constraint)
+                    format!(" + {constraint}")
                 } else {
-                    format!(" {}", constraint)
+                    format!(" {constraint}")
                 },
                 SuggestChangingConstraintsMessage::RestrictBoundFurther,
             ))
@@ -337,7 +337,7 @@ pub fn suggest_constraining_type_params<'a>(
                 generics.tail_span_for_predicate_suggestion(),
                 constraints
                     .iter()
-                    .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
+                    .map(|&(constraint, _)| format!(", {param_name}: {constraint}"))
                     .collect::<String>(),
                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
             ));
@@ -358,7 +358,7 @@ pub fn suggest_constraining_type_params<'a>(
             // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
             suggestions.push((
                 generics.tail_span_for_predicate_suggestion(),
-                format!(" where {}: {}", param_name, constraint),
+                format!(" where {param_name}: {constraint}"),
                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
             ));
             continue;
@@ -371,7 +371,7 @@ pub fn suggest_constraining_type_params<'a>(
         if let Some(colon_span) = param.colon_span {
             suggestions.push((
                 colon_span.shrink_to_hi(),
-                format!(" {}", constraint),
+                format!(" {constraint}"),
                 SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
             ));
             continue;
@@ -383,7 +383,7 @@ pub fn suggest_constraining_type_params<'a>(
         //          - help: consider restricting this type parameter with `T: Foo`
         suggestions.push((
             param.span.shrink_to_hi(),
-            format!(": {}", constraint),
+            format!(": {constraint}"),
             SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
         ));
     }
@@ -401,10 +401,10 @@ pub fn suggest_constraining_type_params<'a>(
                 Cow::from("consider further restricting this bound")
             }
             SuggestChangingConstraintsMessage::RestrictType { ty } => {
-                Cow::from(format!("consider restricting type parameter `{}`", ty))
+                Cow::from(format!("consider restricting type parameter `{ty}`"))
             }
             SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
-                Cow::from(format!("consider further restricting type parameter `{}`", ty))
+                Cow::from(format!("consider further restricting type parameter `{ty}`"))
             }
             SuggestChangingConstraintsMessage::RemoveMaybeUnsized => {
                 Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`")
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 3fdbaf5e947..bf6f082c21c 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -90,9 +90,9 @@ impl<'tcx> TypeError<'tcx> {
             // A naive approach to making sure that we're not reporting silly errors such as:
             // (expected closure, found closure).
             if expected == found {
-                format!("expected {}, found a different {}", expected, found)
+                format!("expected {expected}, found a different {found}")
             } else {
-                format!("expected {}, found {}", expected, found)
+                format!("expected {expected}, found {found}")
             }
         }
 
@@ -131,7 +131,7 @@ impl<'tcx> TypeError<'tcx> {
             )
             .into(),
             ArgCount => "incorrect number of function parameters".into(),
-            FieldMisMatch(adt, field) => format!("field type mismatch: {}.{}", adt, field).into(),
+            FieldMisMatch(adt, field) => format!("field type mismatch: {adt}.{field}").into(),
             RegionsDoesNotOutlive(..) => "lifetime mismatch".into(),
             // Actually naming the region here is a bit confusing because context is lacking
             RegionsInsufficientlyPolymorphic(..) => {
@@ -164,7 +164,7 @@ impl<'tcx> TypeError<'tcx> {
                     ty::IntVarValue::IntType(ty) => ty.name_str(),
                     ty::IntVarValue::UintType(ty) => ty.name_str(),
                 };
-                format!("expected `{}`, found `{}`", expected, found).into()
+                format!("expected `{expected}`, found `{found}`").into()
             }
             FloatMismatch(ref values) => format!(
                 "expected `{}`, found `{}`",
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 48e88daa890..8913bf76d34 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -308,13 +308,13 @@ fn fmt_instance(
         InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
         InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
         InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
-        InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
-        InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),
+        InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"),
+        InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"),
         InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
         InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
-        InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty),
-        InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty),
-        InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({})", ty),
+        InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"),
+        InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"),
+        InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"),
     }
 }
 
@@ -336,9 +336,7 @@ impl<'tcx> Instance<'tcx> {
     pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> {
         assert!(
             !args.has_escaping_bound_vars(),
-            "args of instance {:?} not normalized for codegen: {:?}",
-            def_id,
-            args
+            "args of instance {def_id:?} not normalized for codegen: {args:?}"
         );
         Instance { def: InstanceDef::Item(def_id), args }
     }
@@ -425,7 +423,7 @@ impl<'tcx> Instance<'tcx> {
     ) -> Option<Instance<'tcx>> {
         debug!("resolve(def_id={:?}, args={:?})", def_id, args);
         // Use either `resolve_closure` or `resolve_for_vtable`
-        assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id);
+        assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
         Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 93dabb973e3..0f7bed0845c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -249,9 +249,9 @@ impl<'tcx> LayoutError<'tcx> {
 impl<'tcx> fmt::Display for LayoutError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty),
+            LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
             LayoutError::SizeOverflow(ty) => {
-                write!(f, "values of the type `{}` are too big for the current architecture", ty)
+                write!(f, "values of the type `{ty}` are too big for the current architecture")
             }
             LayoutError::NormalizationFailure(t, e) => write!(
                 f,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f9c0fbb23c3..2b4c834f766 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -958,9 +958,9 @@ pub struct Term<'tcx> {
 impl Debug for Term<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let data = if let Some(ty) = self.ty() {
-            format!("Term::Ty({:?})", ty)
+            format!("Term::Ty({ty:?})")
         } else if let Some(ct) = self.ct() {
-            format!("Term::Ct({:?})", ct)
+            format!("Term::Ct({ct:?})")
         } else {
             unreachable!()
         };
@@ -1359,12 +1359,24 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(self))).to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx)
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(ClauseKind::TypeOutlives(p))).to_predicate(tcx)
@@ -2613,19 +2625,6 @@ impl<'tcx> TyCtxt<'tcx> {
         matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
     }
 
-    pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId {
-        match self.opt_rpitit_info(def_id) {
-            Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
-            | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
-            None => {
-                while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
-                    def_id = self.parent(def_id);
-                }
-                def_id
-            }
-        }
-    }
-
     /// Returns the `DefId` of the item within which the `impl Trait` is declared.
     /// For type-alias-impl-trait this is the `type` alias.
     /// For impl-trait-in-assoc-type this is the assoc type.
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 3c2c4483c73..2415d50b278 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -20,8 +20,8 @@ pub enum NormalizationError<'tcx> {
 impl<'tcx> NormalizationError<'tcx> {
     pub fn get_type_for_failure(&self) -> String {
         match self {
-            NormalizationError::Type(t) => format!("{}", t),
-            NormalizationError::Const(c) => format!("{}", c),
+            NormalizationError::Type(t) => format!("{t}"),
+            NormalizationError::Const(c) => format!("{c}"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 7ae8be2dab3..0ff5ac90304 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -124,7 +124,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
 
         match self.map.get(&r.into()).map(|k| k.unpack()) {
             Some(GenericArgKind::Lifetime(r1)) => r1,
-            Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
+            Some(u) => panic!("region mapped to unexpected kind: {u:?}"),
             None if self.do_not_error => self.tcx.lifetimes.re_static,
             None => {
                 let e = self
@@ -134,9 +134,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                     .span_label(
                         self.span,
                         format!(
-                            "lifetime `{}` is part of concrete type but not used in \
-                             parameter list of the `impl Trait` type alias",
-                            r
+                            "lifetime `{r}` is part of concrete type but not used in \
+                             parameter list of the `impl Trait` type alias"
                         ),
                     )
                     .emit();
@@ -169,7 +168,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                     // Found it in the substitution list; replace with the parameter from the
                     // opaque type.
                     Some(GenericArgKind::Type(t1)) => t1,
-                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
+                    Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
                     None => {
                         debug!(?param, ?self.map);
                         if !self.ignore_errors {
@@ -178,9 +177,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                                 .struct_span_err(
                                     self.span,
                                     format!(
-                                        "type parameter `{}` is part of concrete type but not \
-                                          used in parameter list for the `impl Trait` type alias",
-                                        ty
+                                        "type parameter `{ty}` is part of concrete type but not \
+                                          used in parameter list for the `impl Trait` type alias"
                                     ),
                                 )
                                 .emit();
@@ -205,7 +203,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                     // Found it in the substitution list, replace with the parameter from the
                     // opaque type.
                     Some(GenericArgKind::Const(c1)) => c1,
-                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
+                    Some(u) => panic!("const mapped to unexpected kind: {u:?}"),
                     None => {
                         let guar = self
                             .tcx
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index e5633223464..f146f8aa8b4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -17,6 +17,7 @@ use rustc_hir::LangItem;
 use rustc_session::config::TrimmedDefPaths;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_session::Limit;
+use rustc_span::sym;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::FileNameDisplayPreference;
 use rustc_target::abi::Size;
@@ -1497,7 +1498,7 @@ pub trait PrettyPrinter<'tcx>:
                 let data = int.assert_bits(self.tcx().data_layout.pointer_size);
                 self = self.typed_value(
                     |mut this| {
-                        write!(this, "0x{:x}", data)?;
+                        write!(this, "0x{data:x}")?;
                         Ok(this)
                     },
                     |this| this.print_type(ty),
@@ -1510,7 +1511,7 @@ pub trait PrettyPrinter<'tcx>:
                     if int.size() == Size::ZERO {
                         write!(this, "transmute(())")?;
                     } else {
-                        write!(this, "transmute(0x{:x})", int)?;
+                        write!(this, "transmute(0x{int:x})")?;
                     }
                     Ok(this)
                 };
@@ -2017,11 +2018,37 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
     ) -> Result<Self::Path, Self::Error> {
         self = print_prefix(self)?;
 
-        if args.first().is_some() {
+        let tcx = self.tcx;
+
+        let args = args.iter().copied();
+
+        let args: Vec<_> = if !tcx.sess.verbose() {
+            // skip host param as those are printed as `~const`
+            args.filter(|arg| match arg.unpack() {
+                // FIXME(effects) there should be a better way than just matching the name
+                GenericArgKind::Const(c)
+                    if tcx.features().effects
+                        && matches!(
+                            c.kind(),
+                            ty::ConstKind::Param(ty::ParamConst { name: sym::host, .. })
+                        ) =>
+                {
+                    false
+                }
+                _ => true,
+            })
+            .collect()
+        } else {
+            // If -Zverbose is passed, we should print the host parameter instead
+            // of eating it.
+            args.collect()
+        };
+
+        if !args.is_empty() {
             if self.in_value {
                 write!(self, "::")?;
             }
-            self.generic_delimiters(|cx| cx.comma_sep(args.iter().cloned()))
+            self.generic_delimiters(|cx| cx.comma_sep(args.into_iter()))
         } else {
             Ok(self)
         }
@@ -2348,10 +2375,10 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             } else {
                 cont
             };
-            let _ = write!(cx, "{}", w);
+            let _ = write!(cx, "{w}");
         };
         let do_continue = |cx: &mut Self, cont: Symbol| {
-            let _ = write!(cx, "{}", cont);
+            let _ = write!(cx, "{cont}");
         };
 
         define_scoped_cx!(self);
@@ -2387,7 +2414,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         let (new_value, map) = if self.should_print_verbose() {
             for var in value.bound_vars().iter() {
                 start_or_continue(&mut self, "for<", ", ");
-                write!(self, "{:?}", var)?;
+                write!(self, "{var:?}")?;
             }
             start_or_continue(&mut self, "", "> ");
             (value.clone().skip_binder(), BTreeMap::default())
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 50bf9afa531..c6b6f0e8990 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -73,9 +73,9 @@ impl fmt::Debug for ty::BoundRegionKind {
             ty::BrAnon(span) => write!(f, "BrAnon({span:?})"),
             ty::BrNamed(did, name) => {
                 if did.is_crate_root() {
-                    write!(f, "BrNamed({})", name)
+                    write!(f, "BrNamed({name})")
                 } else {
-                    write!(f, "BrNamed({:?}, {})", did, name)
+                    write!(f, "BrNamed({did:?}, {name})")
                 }
             }
             ty::BrEnv => write!(f, "BrEnv"),
@@ -205,7 +205,7 @@ impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
             ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f),
             ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f),
             ty::ClauseKind::Projection(ref pair) => pair.fmt(f),
-            ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({:?})", data),
+            ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({data:?})"),
             ty::ClauseKind::ConstEvaluatable(ct) => {
                 write!(f, "ConstEvaluatable({ct:?})")
             }
@@ -220,12 +220,12 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
             ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                write!(f, "ObjectSafe({:?})", trait_def_id)
+                write!(f, "ObjectSafe({trait_def_id:?})")
             }
             ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
-                write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_args, kind)
+                write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
             }
-            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
             ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
             ty::PredicateKind::AliasRelate(t1, t2, dir) => {
                 write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
@@ -470,10 +470,8 @@ TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::Unsafety,
     ::rustc_target::asm::InlineAsmRegOrRegClass,
     ::rustc_target::spec::abi::Abi,
-    crate::mir::coverage::ExpressionOperandId,
-    crate::mir::coverage::CounterValueReference,
-    crate::mir::coverage::InjectedExpressionId,
-    crate::mir::coverage::InjectedExpressionIndex,
+    crate::mir::coverage::CounterId,
+    crate::mir::coverage::ExpressionId,
     crate::mir::coverage::MappedExpressionIndex,
     crate::mir::Local,
     crate::mir::Promoted,
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 553b76cad4e..90ecc8aa857 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -57,7 +57,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
                 let x = self.val;
                 // sign extend the raw representation to be an i128
                 let x = size.sign_extend(x) as i128;
-                write!(fmt, "{}", x)
+                write!(fmt, "{x}")
             }
             _ => write!(fmt, "{}", self.val),
         }
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 443791d0af4..97402caa001 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -29,8 +29,8 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
             VtblEntry::MetadataSize => write!(f, "MetadataSize"),
             VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
             VtblEntry::Vacant => write!(f, "Vacant"),
-            VtblEntry::Method(instance) => write!(f, "Method({})", instance),
-            VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
+            VtblEntry::Method(instance) => write!(f, "Method({instance})"),
+            VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({trait_ref})"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index 43ee0343f5a..634ed5ec54b 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -29,7 +29,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
     location: &Location<'_>,
 ) -> ! {
     tls::with_opt(move |tcx| {
-        let msg = format!("{}: {}", location, args);
+        let msg = format!("{location}: {args}");
         match (tcx, span) {
             (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, msg),
             (Some(tcx), None) => tcx.sess.diagnostic().bug(msg),
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index 08977049db0..df101a2f6e4 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -17,7 +17,7 @@ pub fn to_readable_str(mut val: usize) -> String {
             groups.push(group.to_string());
             break;
         } else {
-            groups.push(format!("{:03}", group));
+            groups.push(format!("{group:03}"));
         }
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index fd6b1dc5c07..8d78ec04821 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -1099,10 +1099,10 @@ fn debug_with_context_rec<V: Debug + Eq>(
         let info_elem = map.places[child].proj_elem.unwrap();
         let child_place_str = match info_elem {
             TrackElem::Discriminant => {
-                format!("discriminant({})", place_str)
+                format!("discriminant({place_str})")
             }
             TrackElem::Variant(idx) => {
-                format!("({} as {:?})", place_str, idx)
+                format!("({place_str} as {idx:?})")
             }
             TrackElem::Field(field) => {
                 if place_str.starts_with('*') {
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index e9c5f856d35..97bdb878ab1 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -16,8 +16,8 @@ use rustc_middle::mir::coverage::*;
 /// `Coverage` statements.
 pub(super) struct CoverageCounters {
     function_source_hash: u64,
-    next_counter_id: u32,
-    num_expressions: u32,
+    next_counter_id: CounterId,
+    next_expression_id: ExpressionId,
     pub debug_counters: DebugCounters,
 }
 
@@ -25,8 +25,8 @@ impl CoverageCounters {
     pub fn new(function_source_hash: u64) -> Self {
         Self {
             function_source_hash,
-            next_counter_id: CounterValueReference::START.as_u32(),
-            num_expressions: 0,
+            next_counter_id: CounterId::START,
+            next_expression_id: ExpressionId::START,
             debug_counters: DebugCounters::new(),
         }
     }
@@ -65,9 +65,9 @@ impl CoverageCounters {
 
     fn make_expression<F>(
         &mut self,
-        lhs: ExpressionOperandId,
+        lhs: Operand,
         op: Op,
-        rhs: ExpressionOperandId,
+        rhs: Operand,
         debug_block_label_fn: F,
     ) -> CoverageKind
     where
@@ -81,33 +81,30 @@ impl CoverageCounters {
         expression
     }
 
-    pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind {
+    pub fn make_identity_counter(&mut self, counter_operand: Operand) -> CoverageKind {
         let some_debug_block_label = if self.debug_counters.is_enabled() {
             self.debug_counters.some_block_label(counter_operand).cloned()
         } else {
             None
         };
-        self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || {
+        self.make_expression(counter_operand, Op::Add, Operand::Zero, || {
             some_debug_block_label.clone()
         })
     }
 
     /// Counter IDs start from one and go up.
-    fn next_counter(&mut self) -> CounterValueReference {
-        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
+    fn next_counter(&mut self) -> CounterId {
         let next = self.next_counter_id;
-        self.next_counter_id += 1;
-        CounterValueReference::from(next)
+        self.next_counter_id = next.next_id();
+        next
     }
 
-    /// Expression IDs start from u32::MAX and go down because an Expression can reference
-    /// (add or subtract counts) of both Counter regions and Expression regions. The counter
-    /// expression operand IDs must be unique across both types.
-    fn next_expression(&mut self) -> InjectedExpressionId {
-        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
-        let next = u32::MAX - self.num_expressions;
-        self.num_expressions += 1;
-        InjectedExpressionId::from(next)
+    /// Expression IDs start from 0 and go up.
+    /// (Counter IDs and Expression IDs are distinguished by the `Operand` enum.)
+    fn next_expression(&mut self) -> ExpressionId {
+        let next = self.next_expression_id;
+        self.next_expression_id = next.next_id();
+        next
     }
 }
 
@@ -199,7 +196,7 @@ impl<'a> BcbCounters<'a> {
         &mut self,
         traversal: &mut TraverseCoverageGraphWithLoops,
         branching_bcb: BasicCoverageBlock,
-        branching_counter_operand: ExpressionOperandId,
+        branching_counter_operand: Operand,
         collect_intermediate_expressions: &mut Vec<CoverageKind>,
     ) -> Result<(), Error> {
         let branches = self.bcb_branches(branching_bcb);
@@ -261,7 +258,7 @@ impl<'a> BcbCounters<'a> {
                         "  [new intermediate expression: {}]",
                         self.format_counter(&intermediate_expression)
                     );
-                    let intermediate_expression_operand = intermediate_expression.as_operand_id();
+                    let intermediate_expression_operand = intermediate_expression.as_operand();
                     collect_intermediate_expressions.push(intermediate_expression);
                     some_sumup_counter_operand.replace(intermediate_expression_operand);
                 }
@@ -298,7 +295,7 @@ impl<'a> BcbCounters<'a> {
         &mut self,
         bcb: BasicCoverageBlock,
         collect_intermediate_expressions: &mut Vec<CoverageKind>,
-    ) -> Result<ExpressionOperandId, Error> {
+    ) -> Result<Operand, Error> {
         self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1)
     }
 
@@ -307,7 +304,7 @@ impl<'a> BcbCounters<'a> {
         bcb: BasicCoverageBlock,
         collect_intermediate_expressions: &mut Vec<CoverageKind>,
         debug_indent_level: usize,
-    ) -> Result<ExpressionOperandId, Error> {
+    ) -> Result<Operand, Error> {
         // If the BCB already has a counter, return it.
         if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() {
             debug!(
@@ -316,7 +313,7 @@ impl<'a> BcbCounters<'a> {
                 bcb,
                 self.format_counter(counter_kind),
             );
-            return Ok(counter_kind.as_operand_id());
+            return Ok(counter_kind.as_operand());
         }
 
         // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
@@ -383,7 +380,7 @@ impl<'a> BcbCounters<'a> {
                     NESTED_INDENT.repeat(debug_indent_level),
                     self.format_counter(&intermediate_expression)
                 );
-                let intermediate_expression_operand = intermediate_expression.as_operand_id();
+                let intermediate_expression_operand = intermediate_expression.as_operand();
                 collect_intermediate_expressions.push(intermediate_expression);
                 some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
             }
@@ -408,7 +405,7 @@ impl<'a> BcbCounters<'a> {
         from_bcb: BasicCoverageBlock,
         to_bcb: BasicCoverageBlock,
         collect_intermediate_expressions: &mut Vec<CoverageKind>,
-    ) -> Result<ExpressionOperandId, Error> {
+    ) -> Result<Operand, Error> {
         self.recursive_get_or_make_edge_counter_operand(
             from_bcb,
             to_bcb,
@@ -423,7 +420,7 @@ impl<'a> BcbCounters<'a> {
         to_bcb: BasicCoverageBlock,
         collect_intermediate_expressions: &mut Vec<CoverageKind>,
         debug_indent_level: usize,
-    ) -> Result<ExpressionOperandId, Error> {
+    ) -> Result<Operand, Error> {
         // If the source BCB has only one successor (assumed to be the given target), an edge
         // counter is unnecessary. Just get or make a counter for the source BCB.
         let successors = self.bcb_successors(from_bcb).iter();
@@ -444,7 +441,7 @@ impl<'a> BcbCounters<'a> {
                 to_bcb,
                 self.format_counter(counter_kind)
             );
-            return Ok(counter_kind.as_operand_id());
+            return Ok(counter_kind.as_operand());
         }
 
         // Make a new counter to count this edge.
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index c9914eb9f82..26f9cfd0b86 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -246,7 +246,7 @@ impl Default for ExpressionFormat {
     }
 }
 
-/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to
+/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `Operand`) to
 /// the `CoverageKind` data and optional label (normally, the counter's associated
 /// `BasicCoverageBlock` format string, if any).
 ///
@@ -258,7 +258,7 @@ impl Default for ExpressionFormat {
 /// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
 /// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
 pub(super) struct DebugCounters {
-    some_counters: Option<FxHashMap<ExpressionOperandId, DebugCounter>>,
+    some_counters: Option<FxHashMap<Operand, DebugCounter>>,
 }
 
 impl DebugCounters {
@@ -277,14 +277,14 @@ impl DebugCounters {
 
     pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) {
         if let Some(counters) = &mut self.some_counters {
-            let id = counter_kind.as_operand_id();
+            let id = counter_kind.as_operand();
             counters
                 .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
                 .expect("attempt to add the same counter_kind to DebugCounters more than once");
         }
     }
 
-    pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> {
+    pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
         self.some_counters.as_ref().and_then(|counters| {
             counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
         })
@@ -323,24 +323,24 @@ impl DebugCounters {
             }
         }
 
-        let id = counter_kind.as_operand_id();
+        let id = counter_kind.as_operand();
         if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
             let counters = self.some_counters.as_ref().unwrap();
             if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
                 counters.get(&id)
             {
                 return if counter_format.id {
-                    format!("{}#{}", block_label, id.index())
+                    format!("{}#{:?}", block_label, id)
                 } else {
                     block_label.to_string()
                 };
             }
         }
-        format!("#{}", id.index())
+        format!("#{:?}", id)
     }
 
-    fn format_operand(&self, operand: ExpressionOperandId) -> String {
-        if operand.index() == 0 {
+    fn format_operand(&self, operand: Operand) -> String {
+        if matches!(operand, Operand::Zero) {
             return String::from("0");
         }
         if let Some(counters) = &self.some_counters {
@@ -358,7 +358,7 @@ impl DebugCounters {
                 return self.format_counter_kind(counter_kind);
             }
         }
-        format!("#{}", operand.index())
+        format!("#{:?}", operand)
     }
 }
 
@@ -485,8 +485,7 @@ impl GraphvizData {
 /// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
 /// and/or a `CoverageGraph` graphviz output).
 pub(super) struct UsedExpressions {
-    some_used_expression_operands:
-        Option<FxHashMap<ExpressionOperandId, Vec<InjectedExpressionId>>>,
+    some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
     some_unused_expressions:
         Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
 }
@@ -517,7 +516,7 @@ impl UsedExpressions {
 
     pub fn expression_is_used(&self, expression: &CoverageKind) -> bool {
         if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            used_expression_operands.contains_key(&expression.as_operand_id())
+            used_expression_operands.contains_key(&expression.as_operand())
         } else {
             false
         }
@@ -530,7 +529,7 @@ impl UsedExpressions {
         target_bcb: BasicCoverageBlock,
     ) {
         if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            if !used_expression_operands.contains_key(&expression.as_operand_id()) {
+            if !used_expression_operands.contains_key(&expression.as_operand()) {
                 self.some_unused_expressions.as_mut().unwrap().push((
                     expression.clone(),
                     edge_from_bcb,
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 5d843f4ade0..f94dad4c8da 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -345,10 +345,7 @@ impl BasicCoverageBlockData {
         &mir_body[self.last_bb()].terminator()
     }
 
-    pub fn set_counter(
-        &mut self,
-        counter_kind: CoverageKind,
-    ) -> Result<ExpressionOperandId, Error> {
+    pub fn set_counter(&mut self, counter_kind: CoverageKind) -> Result<Operand, Error> {
         debug_assert!(
             // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
             // have an expression (to be injected into an existing `BasicBlock` represented by this
@@ -356,7 +353,7 @@ impl BasicCoverageBlockData {
             self.edge_from_bcbs.is_none() || counter_kind.is_expression(),
             "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
         );
-        let operand = counter_kind.as_operand_id();
+        let operand = counter_kind.as_operand();
         if let Some(replaced) = self.counter_kind.replace(counter_kind) {
             Error::from_string(format!(
                 "attempt to set a BasicCoverageBlock coverage counter more than once; \
@@ -381,7 +378,7 @@ impl BasicCoverageBlockData {
         &mut self,
         from_bcb: BasicCoverageBlock,
         counter_kind: CoverageKind,
-    ) -> Result<ExpressionOperandId, Error> {
+    ) -> Result<Operand, Error> {
         if level_enabled!(tracing::Level::DEBUG) {
             // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
             // have an expression (to be injected into an existing `BasicBlock` represented by this
@@ -393,7 +390,7 @@ impl BasicCoverageBlockData {
                 ));
             }
         }
-        let operand = counter_kind.as_operand_id();
+        let operand = counter_kind.as_operand();
         if let Some(replaced) =
             self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind)
         {
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 076e714d703..f713613d313 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -304,7 +304,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
             let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {
                 self.coverage_counters.make_identity_counter(counter_operand)
             } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() {
-                bcb_counters[bcb] = Some(counter_kind.as_operand_id());
+                bcb_counters[bcb] = Some(counter_kind.as_operand());
                 debug_used_expressions.add_expression_operands(&counter_kind);
                 counter_kind
             } else {
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 74b4b4a07c5..aa205655f9d 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -43,43 +43,25 @@ struct CoverageVisitor {
 }
 
 impl CoverageVisitor {
-    /// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the
-    /// final computed number of counters should be the number of all `CoverageKind::Counter`
-    /// statements in the MIR *plus one* for the implicit `ZERO` counter.
+    /// Updates `num_counters` to the maximum encountered counter ID plus 1.
     #[inline(always)]
-    fn update_num_counters(&mut self, counter_id: u32) {
+    fn update_num_counters(&mut self, counter_id: CounterId) {
+        let counter_id = counter_id.as_u32();
         self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
     }
 
-    /// Computes an expression index for each expression ID, and updates `num_expressions` to the
-    /// maximum encountered index plus 1.
+    /// Updates `num_expressions` to the maximum encountered expression ID plus 1.
     #[inline(always)]
-    fn update_num_expressions(&mut self, expression_id: u32) {
-        let expression_index = u32::MAX - expression_id;
-        self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
+    fn update_num_expressions(&mut self, expression_id: ExpressionId) {
+        let expression_id = expression_id.as_u32();
+        self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1);
     }
 
-    fn update_from_expression_operand(&mut self, operand_id: u32) {
-        if operand_id >= self.info.num_counters {
-            let operand_as_expression_index = u32::MAX - operand_id;
-            if operand_as_expression_index >= self.info.num_expressions {
-                // The operand ID is outside the known range of counter IDs and also outside the
-                // known range of expression IDs. In either case, the result of a missing operand
-                // (if and when used in an expression) will be zero, so from a computation
-                // perspective, it doesn't matter whether it is interpreted as a counter or an
-                // expression.
-                //
-                // However, the `num_counters` and `num_expressions` query results are used to
-                // allocate arrays when generating the coverage map (during codegen), so choose
-                // the type that grows either `num_counters` or `num_expressions` the least.
-                if operand_id - self.info.num_counters
-                    < operand_as_expression_index - self.info.num_expressions
-                {
-                    self.update_num_counters(operand_id)
-                } else {
-                    self.update_num_expressions(operand_id)
-                }
-            }
+    fn update_from_expression_operand(&mut self, operand: Operand) {
+        match operand {
+            Operand::Counter(id) => self.update_num_counters(id),
+            Operand::Expression(id) => self.update_num_expressions(id),
+            Operand::Zero => {}
         }
     }
 
@@ -100,19 +82,15 @@ impl CoverageVisitor {
         if self.add_missing_operands {
             match coverage.kind {
                 CoverageKind::Expression { lhs, rhs, .. } => {
-                    self.update_from_expression_operand(u32::from(lhs));
-                    self.update_from_expression_operand(u32::from(rhs));
+                    self.update_from_expression_operand(lhs);
+                    self.update_from_expression_operand(rhs);
                 }
                 _ => {}
             }
         } else {
             match coverage.kind {
-                CoverageKind::Counter { id, .. } => {
-                    self.update_num_counters(u32::from(id));
-                }
-                CoverageKind::Expression { id, .. } => {
-                    self.update_num_expressions(u32::from(id));
-                }
+                CoverageKind::Counter { id, .. } => self.update_num_counters(id),
+                CoverageKind::Expression { id, .. } => self.update_num_expressions(id),
                 _ => {}
             }
         }
@@ -123,8 +101,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
     let mir_body = tcx.instance_mir(instance_def);
 
     let mut coverage_visitor = CoverageVisitor {
-        // num_counters always has at least the `ZERO` counter.
-        info: CoverageInfo { num_counters: 1, num_expressions: 0 },
+        info: CoverageInfo { num_counters: 0, num_expressions: 0 },
         add_missing_operands: false,
     };
 
diff --git a/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs b/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
index 3d6095d2738..f41adf667ec 100644
--- a/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
@@ -2,5 +2,5 @@ use proc_macro::TokenStream;
 
 #[proc_macro]
 pub fn let_bcb(item: TokenStream) -> TokenStream {
-    format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap()
+    format!("let bcb{item} = graph::BasicCoverageBlock::from_usize({item});").parse().unwrap()
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 25891d3ca0f..248a192f8f5 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -683,7 +683,7 @@ fn test_make_bcb_counters() {
 
         let_bcb!(1);
         assert_eq!(
-            1, // coincidentally, bcb1 has a `Counter` with id = 1
+            0, // bcb1 has a `Counter` with id = 0
             match basic_coverage_blocks[bcb1].counter().expect("should have a counter") {
                 CoverageKind::Counter { id, .. } => id,
                 _ => panic!("expected a Counter"),
@@ -693,7 +693,7 @@ fn test_make_bcb_counters() {
 
         let_bcb!(2);
         assert_eq!(
-            2, // coincidentally, bcb2 has a `Counter` with id = 2
+            1, // bcb2 has a `Counter` with id = 1
             match basic_coverage_blocks[bcb2].counter().expect("should have a counter") {
                 CoverageKind::Counter { id, .. } => id,
                 _ => panic!("expected a Counter"),
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 4f1d282fe7d..83d96ad8e76 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -724,6 +724,10 @@ parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
 
 parse_switch_mut_let_order =
     switch the order of `mut` and `let`
+
+parse_ternary_operator = Rust has no ternary operator
+    .help = use an `if-else` expression instead
+
 parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
 
 parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 5456a708898..06c09960727 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -365,6 +365,14 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
     AddThenBlock(#[primary_span] Span),
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_ternary_operator)]
+#[help]
+pub struct TernaryOperator {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 #[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")]
 pub(crate) struct IfExpressionLetSomeSub {
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 9e6d27bf036..b50bb47f297 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -46,7 +46,7 @@ pub fn report_missing_open_delim(
             };
             err.span_label(
                 unmatch_brace.found_span.shrink_to_lo(),
-                format!("missing open `{}` for this delimiter", missed_open),
+                format!("missing open `{missed_open}` for this delimiter"),
             );
             reported_missing_open = true;
         }
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 318a2998509..07910113dee 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -198,7 +198,7 @@ impl<'a> TokenTreesReader<'a> {
         // An unexpected closing delimiter (i.e., there is no
         // matching opening delimiter).
         let token_str = token_to_string(&self.token);
-        let msg = format!("unexpected closing delimiter: `{}`", token_str);
+        let msg = format!("unexpected closing delimiter: `{token_str}`");
         let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
 
         report_suspicious_mismatch_block(
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index d1f852b1a40..446472d1294 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -135,7 +135,7 @@ pub(crate) fn emit_unescape_error(
                 "unknown character escape"
             };
             let ec = escaped_char(c);
-            let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
+            let mut diag = handler.struct_span_err(span, format!("{label}: `{ec}`"));
             diag.span_label(span, label);
             if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
                 diag.help(
@@ -151,7 +151,7 @@ pub(crate) fn emit_unescape_error(
                     diag.span_suggestion(
                         span_with_quotes,
                         "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
-                        format!("r\"{}\"", lit),
+                        format!("r\"{lit}\""),
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -180,21 +180,20 @@ pub(crate) fn emit_unescape_error(
                 Mode::RawByteStr => "raw byte string literal",
                 _ => panic!("non-is_byte literal paired with NonAsciiCharInByte"),
             };
-            let mut err = handler.struct_span_err(span, format!("non-ASCII character in {}", desc));
+            let mut err = handler.struct_span_err(span, format!("non-ASCII character in {desc}"));
             let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
-                format!(" but is {:?}", c)
+                format!(" but is {c:?}")
             } else {
                 String::new()
             };
-            err.span_label(span, format!("must be ASCII{}", postfix));
+            err.span_label(span, format!("must be ASCII{postfix}"));
             // Note: the \\xHH suggestions are not given for raw byte string
             // literals, because they are araw and so cannot use any escapes.
             if (c as u32) <= 0xFF && mode != Mode::RawByteStr {
                 err.span_suggestion(
                     span,
                     format!(
-                        "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
-                        c
+                        "if you meant to use the unicode code point for {c:?}, use a \\xHH escape"
                     ),
                     format!("\\x{:X}", c as u32),
                     Applicability::MaybeIncorrect,
@@ -206,7 +205,7 @@ pub(crate) fn emit_unescape_error(
                 utf8.push(c);
                 err.span_suggestion(
                     span,
-                    format!("if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes", c),
+                    format!("if you meant to use the UTF-8 encoding of {c:?}, use \\xHH escapes"),
                     utf8.as_bytes()
                         .iter()
                         .map(|b: &u8| format!("\\x{:X}", *b))
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 829d9693e55..bbfb160ebf7 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -349,7 +349,7 @@ pub(super) fn check_for_substitution(
     let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
 
     let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
-        let msg = format!("substitution character not found for '{}'", ch);
+        let msg = format!("substitution character not found for '{ch}'");
         reader.sess.span_diagnostic.span_bug_no_panic(span, msg);
         return (None, None);
     };
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 25de7808532..6712db26693 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -205,7 +205,7 @@ pub fn stream_to_parser<'a>(
     stream: TokenStream,
     subparser_name: Option<&'static str>,
 ) -> Parser<'a> {
-    Parser::new(sess, stream, false, subparser_name)
+    Parser::new(sess, stream, subparser_name)
 }
 
 /// Runs the given subparser `f` on the tokens of the given `attr`'s item.
@@ -215,7 +215,7 @@ pub fn parse_in<'a, T>(
     name: &'static str,
     mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
 ) -> PResult<'a, T> {
-    let mut parser = Parser::new(sess, tts, false, Some(name));
+    let mut parser = Parser::new(sess, tts, Some(name));
     let result = f(&mut parser)?;
     if parser.token != token::Eof {
         parser.unexpected()?;
@@ -247,7 +247,7 @@ pub fn parse_cfg_attr(
             match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
                 Ok(r) => return Some(r),
                 Err(mut e) => {
-                    e.help(format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+                    e.help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`"))
                         .note(CFG_ATTR_NOTE_REF)
                         .emit();
                 }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 4cc03664b47..158ab2a2956 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -145,13 +145,11 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             // another replace range will capture the *replaced* tokens for the inner
             // range, not the original tokens.
             for (range, new_tokens) in replace_ranges.into_iter().rev() {
-                assert!(!range.is_empty(), "Cannot replace an empty range: {:?}", range);
+                assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}");
                 // Replace ranges are only allowed to decrease the number of tokens.
                 assert!(
                     range.len() >= new_tokens.len(),
-                    "Range {:?} has greater len than {:?}",
-                    range,
-                    new_tokens
+                    "Range {range:?} has greater len than {new_tokens:?}"
                 );
 
                 // Replace any removed tokens with `FlatToken::Empty`.
@@ -409,22 +407,19 @@ fn make_token_stream(
             FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
                 let frame_data = stack
                     .pop()
-                    .unwrap_or_else(|| panic!("Token stack was empty for token: {:?}", token));
+                    .unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}"));
 
                 let (open_delim, open_sp) = frame_data.open_delim_sp.unwrap();
                 assert_eq!(
                     open_delim, delim,
-                    "Mismatched open/close delims: open={:?} close={:?}",
-                    open_delim, span
+                    "Mismatched open/close delims: open={open_delim:?} close={span:?}"
                 );
                 let dspan = DelimSpan::from_pair(open_sp, span);
                 let stream = AttrTokenStream::new(frame_data.inner);
                 let delimited = AttrTokenTree::Delimited(dspan, delim, stream);
                 stack
                     .last_mut()
-                    .unwrap_or_else(|| {
-                        panic!("Bottom token frame is missing for token: {:?}", token)
-                    })
+                    .unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}"))
                     .inner
                     .push(delimited);
             }
@@ -456,7 +451,7 @@ fn make_token_stream(
                 .inner
                 .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
         } else {
-            panic!("Unexpected last token {:?}", last_token)
+            panic!("Unexpected last token {last_token:?}")
         }
     }
     AttrTokenStream::new(final_buf.inner)
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index c3cf6437afa..e6de51a673c 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -14,7 +14,7 @@ use crate::errors::{
     PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
     StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
     StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
-    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+    TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
     UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
 };
 
@@ -500,6 +500,10 @@ impl<'a> Parser<'a> {
 
         // Special-case "expected `;`" errors
         if expected.contains(&TokenType::Token(token::Semi)) {
+            if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() {
+                return Ok(true);
+            }
+
             if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
                 // Likely inside a macro, can't provide meaningful suggestions.
             } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
@@ -608,13 +612,13 @@ impl<'a> Parser<'a> {
         if let TokenKind::Ident(prev, _) = &self.prev_token.kind
           && let TokenKind::Ident(cur, _) = &self.token.kind
         {
-                let concat = Symbol::intern(&format!("{}{}", prev, cur));
+                let concat = Symbol::intern(&format!("{prev}{cur}"));
                 let ident = Ident::new(concat, DUMMY_SP);
                 if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() {
                     let span = self.prev_token.span.to(self.token.span);
                     err.span_suggestion_verbose(
                         span,
-                        format!("consider removing the space to spell keyword `{}`", concat),
+                        format!("consider removing the space to spell keyword `{concat}`"),
                         concat,
                         Applicability::MachineApplicable,
                     );
@@ -1330,6 +1334,45 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Rust has no ternary operator (`cond ? then : else`). Parse it and try
+    /// to recover from it if `then` and `else` are valid expressions. Returns
+    /// whether it was a ternary operator.
+    pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool {
+        if self.prev_token != token::Question {
+            return false;
+        }
+
+        let lo = self.prev_token.span.lo();
+        let snapshot = self.create_snapshot_for_diagnostic();
+
+        if match self.parse_expr() {
+            Ok(_) => true,
+            Err(err) => {
+                err.cancel();
+                // The colon can sometimes be mistaken for type
+                // ascription. Catch when this happens and continue.
+                self.token == token::Colon
+            }
+        } {
+            if self.eat_noexpect(&token::Colon) {
+                match self.parse_expr() {
+                    Ok(_) => {
+                        self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) });
+                        return true;
+                    }
+                    Err(err) => {
+                        err.cancel();
+                        self.restore_snapshot(snapshot);
+                    }
+                };
+            }
+        } else {
+            self.restore_snapshot(snapshot);
+        };
+
+        false
+    }
+
     pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
         if !self.token.is_like_plus() {
@@ -2111,7 +2154,7 @@ impl<'a> Parser<'a> {
             }
             _ => (
                 self.token.span,
-                format!("expected expression, found {}", super::token_descr(&self.token),),
+                format!("expected expression, found {}", super::token_descr(&self.token)),
             ),
         };
         let mut err = self.struct_span_err(span, msg);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b54cb8c5a0c..55f857aa31c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1052,7 +1052,7 @@ impl<'a> Parser<'a> {
                 }
                 components.push(Punct(c));
             } else {
-                panic!("unexpected character in a float token: {:?}", c)
+                panic!("unexpected character in a float token: {c:?}")
             }
         }
         if !ident_like.is_empty() {
@@ -1113,7 +1113,7 @@ impl<'a> Parser<'a> {
                 self.error_unexpected_after_dot();
                 DestructuredFloat::Error
             }
-            _ => panic!("unexpected components in a float token: {:?}", components),
+            _ => panic!("unexpected components in a float token: {components:?}"),
         }
     }
 
@@ -2342,7 +2342,7 @@ impl<'a> Parser<'a> {
             let ty = if this.eat(&token::Colon) {
                 this.parse_ty()?
             } else {
-                this.mk_ty(this.prev_token.span, TyKind::Infer)
+                this.mk_ty(pat.span, TyKind::Infer)
             };
 
             Ok((
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 37b4c371c94..57778d67098 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -24,7 +24,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern};
+use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern};
 use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
@@ -38,7 +38,7 @@ use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use std::ops::Range;
-use std::{cmp, mem, slice};
+use std::{mem, slice};
 use thin_vec::ThinVec;
 use tracing::debug;
 
@@ -224,11 +224,6 @@ struct TokenCursor {
     // because it's the outermost token stream which never has delimiters.
     stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>,
 
-    // We need to desugar doc comments from `/// foo` form into `#[doc =
-    // r"foo"]` form when parsing declarative macro inputs in `parse_tt`,
-    // because some declarative macros look for `doc` attributes.
-    desugar_doc_comments: bool,
-
     // Counts the number of calls to `{,inlined_}next`.
     num_next_calls: usize,
 
@@ -265,29 +260,17 @@ impl TokenCursor {
     #[inline(always)]
     fn inlined_next(&mut self) -> (Token, Spacing) {
         loop {
-            // FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will
-            // need to, whereupon the `delim != Delimiter::Invisible` conditions below can be
-            // removed.
+            // FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix
+            // #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions
+            // below can be removed.
             if let Some(tree) = self.tree_cursor.next_ref() {
                 match tree {
                     &TokenTree::Token(ref token, spacing) => {
-                        match (self.desugar_doc_comments, token) {
-                            (
-                                true,
-                                &Token { kind: token::DocComment(_, attr_style, data), span },
-                            ) => {
-                                let desugared = self.desugar(attr_style, data, span);
-                                self.tree_cursor.replace_prev_and_rewind(desugared);
-                                // Continue to get the first token of the desugared doc comment.
-                            }
-                            _ => {
-                                debug_assert!(!matches!(
-                                    token.kind,
-                                    token::OpenDelim(_) | token::CloseDelim(_)
-                                ));
-                                return (token.clone(), spacing);
-                            }
-                        }
+                        debug_assert!(!matches!(
+                            token.kind,
+                            token::OpenDelim(_) | token::CloseDelim(_)
+                        ));
+                        return (token.clone(), spacing);
                     }
                     &TokenTree::Delimited(sp, delim, ref tts) => {
                         let trees = tts.clone().into_trees();
@@ -311,52 +294,6 @@ impl TokenCursor {
             }
         }
     }
-
-    // Desugar a doc comment into something like `#[doc = r"foo"]`.
-    fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
-        // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
-        // required to wrap the text. E.g.
-        // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
-        // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
-        // - `abc "##d##"` is wrapped as `r###"abc ##"d"##"###` (num_of_hashes = 3)
-        let mut num_of_hashes = 0;
-        let mut count = 0;
-        for ch in data.as_str().chars() {
-            count = match ch {
-                '"' => 1,
-                '#' if count > 0 => count + 1,
-                _ => 0,
-            };
-            num_of_hashes = cmp::max(num_of_hashes, count);
-        }
-
-        // `/// foo` becomes `doc = r"foo"`.
-        let delim_span = DelimSpan::from_single(span);
-        let body = TokenTree::Delimited(
-            delim_span,
-            Delimiter::Bracket,
-            [
-                TokenTree::token_alone(token::Ident(sym::doc, false), span),
-                TokenTree::token_alone(token::Eq, span),
-                TokenTree::token_alone(
-                    TokenKind::lit(token::StrRaw(num_of_hashes), data, None),
-                    span,
-                ),
-            ]
-            .into_iter()
-            .collect::<TokenStream>(),
-        );
-
-        if attr_style == AttrStyle::Inner {
-            vec![
-                TokenTree::token_alone(token::Pound, span),
-                TokenTree::token_alone(token::Not, span),
-                body,
-            ]
-        } else {
-            vec![TokenTree::token_alone(token::Pound, span), body]
-        }
-    }
 }
 
 #[derive(Debug, Clone, PartialEq)]
@@ -375,7 +312,7 @@ impl TokenType {
     fn to_string(&self) -> String {
         match self {
             TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)),
-            TokenType::Keyword(kw) => format!("`{}`", kw),
+            TokenType::Keyword(kw) => format!("`{kw}`"),
             TokenType::Operator => "an operator".to_string(),
             TokenType::Lifetime => "lifetime".to_string(),
             TokenType::Ident => "identifier".to_string(),
@@ -445,14 +382,13 @@ pub(super) fn token_descr(token: &Token) -> String {
         TokenDescription::DocComment => "doc comment",
     });
 
-    if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) }
+    if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
 }
 
 impl<'a> Parser<'a> {
     pub fn new(
         sess: &'a ParseSess,
-        tokens: TokenStream,
-        desugar_doc_comments: bool,
+        stream: TokenStream,
         subparser_name: Option<&'static str>,
     ) -> Self {
         let mut parser = Parser {
@@ -464,10 +400,9 @@ impl<'a> Parser<'a> {
             restrictions: Restrictions::empty(),
             expected_tokens: Vec::new(),
             token_cursor: TokenCursor {
-                tree_cursor: tokens.into_trees(),
+                tree_cursor: stream.into_trees(),
                 stack: Vec::new(),
                 num_next_calls: 0,
-                desugar_doc_comments,
                 break_last_token: false,
             },
             unmatched_angle_bracket_count: 0,
@@ -929,7 +864,7 @@ impl<'a> Parser<'a> {
                                     expect_err
                                         .span_suggestion_short(
                                             sp,
-                                            format!("missing `{}`", token_str),
+                                            format!("missing `{token_str}`"),
                                             token_str,
                                             Applicability::MaybeIncorrect,
                                         )
@@ -1172,7 +1107,7 @@ impl<'a> Parser<'a> {
             }
             i += 1;
         }
-        return looker(&token);
+        looker(&token)
     }
 
     /// Returns whether any of the given keywords are `dist` tokens ahead of the current one.
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 14891c45d81..fed16278db5 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -428,7 +428,7 @@ impl<'a> Parser<'a> {
                     );
 
                     let mut err = self_.struct_span_err(self_.token.span, msg);
-                    err.span_label(self_.token.span, format!("expected {}", expected));
+                    err.span_label(self_.token.span, format!("expected {expected}"));
                     err
                 });
             PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
@@ -664,7 +664,7 @@ impl<'a> Parser<'a> {
         let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
 
         let mut err = self.struct_span_err(self.token.span, msg);
-        err.span_label(self.token.span, format!("expected {}", expected));
+        err.span_label(self.token.span, format!("expected {expected}"));
 
         let sp = self.sess.source_map().start_point(self.token.span);
         if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
@@ -977,7 +977,7 @@ impl<'a> Parser<'a> {
                     break;
                 }
                 let token_str = super::token_descr(&self.token);
-                let msg = format!("expected `}}`, found {}", token_str);
+                let msg = format!("expected `}}`, found {token_str}");
                 let mut err = self.struct_span_err(self.token.span, msg);
 
                 err.span_label(self.token.span, "expected `}`");
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index feb7e829caf..445516c03a1 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -679,7 +679,7 @@ impl<'a> Parser<'a> {
                     );
                     err.span_suggestion(
                         eq.to(before_next),
-                        format!("remove the `=` if `{}` is a type", ident),
+                        format!("remove the `=` if `{ident}` is a type"),
                         "",
                         Applicability::MaybeIncorrect,
                     )
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 9fcf51a04ec..1cdf2efa764 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -300,7 +300,7 @@ impl<'a> Parser<'a> {
                 Ok(ty) => (None, Some(ty)),
                 Err(mut err) => {
                     if let Ok(snip) = self.span_to_snippet(pat.span) {
-                        err.span_label(pat.span, format!("while parsing the type for `{}`", snip));
+                        err.span_label(pat.span, format!("while parsing the type for `{snip}`"));
                     }
                     // we use noexpect here because we don't actually expect Eq to be here
                     // but we are still checking for it in order to be able to handle it if
@@ -502,7 +502,7 @@ impl<'a> Parser<'a> {
 
     fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
         let tok = super::token_descr(&self.token);
-        let msg = format!("expected `{{`, found {}", tok);
+        let msg = format!("expected `{{`, found {tok}");
         Err(self.error_block_no_opening_brace_msg(Cow::from(msg)))
     }
 
@@ -638,10 +638,9 @@ impl<'a> Parser<'a> {
                                 e.span_suggestion(
                                     sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
                                     format!(
-                                        "add a space before `{}` to use a regular comment",
-                                        doc_comment_marker,
+                                        "add a space before `{doc_comment_marker}` to use a regular comment",
                                     ),
-                                    format!("{} {}", comment_marker, doc_comment_marker),
+                                    format!("{comment_marker} {doc_comment_marker}"),
                                     Applicability::MaybeIncorrect,
                                 );
                             }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e2827252509..5fa780a372b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1941,7 +1941,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
         let reexported_at_vis = effective_vis.at_level(Level::Reexported);
         let reachable_at_vis = effective_vis.at_level(Level::Reachable);
 
-        if reexported_at_vis != reachable_at_vis {
+        if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
             let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
             let span = self.tcx.def_span(def_id.to_def_id());
             self.tcx.emit_spanned_lint(
@@ -1973,10 +1973,6 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
             AssocItemKind::Type => (self.tcx.defaultness(def_id).has_value(), true),
         };
 
-        if is_assoc_ty {
-            self.check_unnameable(def_id, self.get(def_id));
-        }
-
         check.in_assoc_ty = is_assoc_ty;
         check.generics().predicates();
         if check_ty {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index c9e80a6d9bc..b87757a3e1a 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -557,7 +557,7 @@ impl<K: DepKind> DepGraph<K> {
                         result,
                         prev_index,
                         hash_result,
-                        |value| format!("{:?}", value),
+                        |value| format!("{value:?}"),
                     );
 
                     #[cfg(debug_assertions)]
@@ -1433,7 +1433,7 @@ pub(crate) fn print_markframe_trace<K: DepKind>(
     let mut current = frame;
     while let Some(frame) = current {
         let node = data.previous.index_to_node(frame.index);
-        eprintln!("#{i} {:?}", node);
+        eprintln!("#{i} {node:?}");
         current = frame.parent;
         i += 1;
     }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 5814e3d6c13..2f432799022 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1001,7 +1001,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         allow_shadowing: bool,
     ) {
         if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
-            let msg = format!("`{}` is already in scope", name);
+            let msg = format!("`{name}` is already in scope");
             let note =
                 "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
             self.r.tcx.sess.struct_span_err(span, msg).note(note).emit();
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 3228e8d52f0..7dbbd4c34ea 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -362,7 +362,7 @@ impl Resolver<'_, '_> {
             let mut span_snippets = spans
                 .iter()
                 .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
-                    Ok(s) => Some(format!("`{}`", s)),
+                    Ok(s) => Some(format!("`{s}`")),
                     _ => None,
                 })
                 .collect::<Vec<String>>();
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 97ac6891d82..cd1a9b934cf 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -243,7 +243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             (TypeNS, _) => "type",
         };
 
-        let msg = format!("the name `{}` is defined multiple times", name);
+        let msg = format!("the name `{name}` is defined multiple times");
 
         let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
             (true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg),
@@ -265,11 +265,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             container
         ));
 
-        err.span_label(span, format!("`{}` re{} here", name, new_participle));
+        err.span_label(span, format!("`{name}` re{new_participle} here"));
         if !old_binding.span.is_dummy() && old_binding.span != span {
             err.span_label(
                 self.tcx.sess.source_map().guess_head_span(old_binding.span),
-                format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+                format!("previous {old_noun} of the {old_kind} `{name}` here"),
             );
         }
 
@@ -358,15 +358,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         binding_span: Span,
     ) {
         let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
-            format!("Other{}", name)
+            format!("Other{name}")
         } else {
-            format!("other_{}", name)
+            format!("other_{name}")
         };
 
         let mut suggestion = None;
         match import.kind {
             ImportKind::Single { type_ns_only: true, .. } => {
-                suggestion = Some(format!("self as {}", suggested_name))
+                suggestion = Some(format!("self as {suggested_name}"))
             }
             ImportKind::Single { source, .. } => {
                 if let Some(pos) =
@@ -602,11 +602,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let sugg_msg = "try using a local generic parameter instead";
                     let name = self.tcx.item_name(def_id);
                     let (span, snippet) = if span.is_empty() {
-                        let snippet = format!("<{}>", name);
+                        let snippet = format!("<{name}>");
                         (span, snippet)
                     } else {
                         let span = sm.span_through_char(span, '<').shrink_to_hi();
-                        let snippet = format!("{}, ", name);
+                        let snippet = format!("{name}, ");
                         (span, snippet)
                     };
                     // Suggest the modification to the user
@@ -667,7 +667,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     name,
                 );
                 for sp in target_sp {
-                    err.span_label(sp, format!("pattern doesn't bind `{}`", name));
+                    err.span_label(sp, format!("pattern doesn't bind `{name}`"));
                 }
                 for sp in origin_sp {
                     err.span_label(sp, "variable not in all patterns");
@@ -694,8 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if import_suggestions.is_empty() {
                         let help_msg = format!(
                             "if you meant to match on a variant or a `const` item, consider \
-                             making the path in the pattern qualified: `path::to::ModOrType::{}`",
-                            name,
+                             making the path in the pattern qualified: `path::to::ModOrType::{name}`",
                         );
                         err.span_help(span, help_msg);
                     }
@@ -953,8 +952,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let mut err = self.tcx.sess.struct_span_err_with_code(
                     span,
                     format!(
-                        "item `{}` is an associated {}, which doesn't match its trait `{}`",
-                        name, kind, trait_path,
+                        "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
                     ),
                     code,
                 );
@@ -1427,10 +1425,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         "a function-like macro".to_string()
                     }
                     Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
-                        format!("an attribute: `#[{}]`", ident)
+                        format!("an attribute: `#[{ident}]`")
                     }
                     Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
-                        format!("a derive macro: `#[derive({})]`", ident)
+                        format!("a derive macro: `#[derive({ident})]`")
                     }
                     Res::ToolMod => {
                         // Don't confuse the user with tool modules.
@@ -1451,7 +1449,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if !import.span.is_dummy() {
                         err.span_note(
                             import.span,
-                            format!("`{}` is imported here, but it is {}", ident, desc),
+                            format!("`{ident}` is imported here, but it is {desc}"),
                         );
                         // Silence the 'unused import' warning we might get,
                         // since this diagnostic already covers that import.
@@ -1459,7 +1457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         return;
                     }
                 }
-                err.note(format!("`{}` is in scope, but it is {}", ident, desc));
+                err.note(format!("`{ident}` is in scope, but it is {desc}"));
                 return;
             }
         }
@@ -1597,7 +1595,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     .enumerate()
                     .map(|(i, help_msg)| {
                         let or = if i == 0 { "" } else { "or " };
-                        format!("{}{}", or, help_msg)
+                        format!("{or}{help_msg}")
                     })
                     .collect::<Vec<_>>(),
             )
@@ -1655,7 +1653,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let descr = get_descr(binding);
         let mut err =
             struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
-        err.span_label(ident.span, format!("private {}", descr));
+        err.span_label(ident.span, format!("private {descr}"));
 
         if let Some((this_res, outer_ident)) = outermost_res {
             let import_suggestions = self.lookup_import_candidates(
@@ -1840,7 +1838,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 _ => format!("`{parent}`"),
             };
 
-            let mut msg = format!("could not find `{}` in {}", ident, parent);
+            let mut msg = format!("could not find `{ident}` in {parent}");
             if ns == TypeNS || ns == ValueNS {
                 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
                 let binding = if let Some(module) = module {
@@ -1955,12 +1953,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let suggestion = match_span.map(|span| {
                 (
                     vec![(span, String::from(""))],
-                    format!("`{}` is defined here, but is not a type", ident),
+                    format!("`{ident}` is defined here, but is not a type"),
                     Applicability::MaybeIncorrect,
                 )
             });
 
-            (format!("use of undeclared type `{}`", ident), suggestion)
+            (format!("use of undeclared type `{ident}`"), suggestion)
         } else {
             let mut suggestion = None;
             if ident.name == sym::alloc {
@@ -1982,7 +1980,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     },
                 )
             });
-            (format!("use of undeclared crate or module `{}`", ident), suggestion)
+            (format!("use of undeclared crate or module `{ident}`"), suggestion)
         }
     }
 
@@ -2166,16 +2164,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let module_name = crate_module.kind.name().unwrap();
             let import_snippet = match import.kind {
                 ImportKind::Single { source, target, .. } if source != target => {
-                    format!("{} as {}", source, target)
+                    format!("{source} as {target}")
                 }
-                _ => format!("{}", ident),
+                _ => format!("{ident}"),
             };
 
             let mut corrections: Vec<(Span, String)> = Vec::new();
             if !import.is_nested() {
                 // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
                 // intermediate segments.
-                corrections.push((import.span, format!("{}::{}", module_name, import_snippet)));
+                corrections.push((import.span, format!("{module_name}::{import_snippet}")));
             } else {
                 // Find the binding span (and any trailing commas and spaces).
                 //   ie. `use a::b::{c, d, e};`
@@ -2242,11 +2240,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         start_point,
                         if has_nested {
                             // In this case, `start_snippet` must equal '{'.
-                            format!("{}{}, ", start_snippet, import_snippet)
+                            format!("{start_snippet}{import_snippet}, ")
                         } else {
                             // In this case, add a `{`, then the moved import, then whatever
                             // was there before.
-                            format!("{{{}, {}", import_snippet, start_snippet)
+                            format!("{{{import_snippet}, {start_snippet}")
                         },
                     ));
 
@@ -2663,9 +2661,9 @@ fn show_candidates(
                 "item"
             };
             let plural_descr =
-                if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
+                if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
 
-            let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
+            let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
             let mut has_colon = false;
 
             let mut spans = Vec::new();
@@ -2686,7 +2684,7 @@ fn show_candidates(
 
             let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
             for (name, span) in spans {
-                multi_span.push_span_label(span, format!("`{}`: not accessible", name));
+                multi_span.push_span_label(span, format!("`{name}`: not accessible"));
             }
 
             for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 00282df700b..3bd9cea27ce 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1445,12 +1445,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let name_str = if name == kw::PathRoot {
                         "crate root".to_string()
                     } else {
-                        format!("`{}`", name)
+                        format!("`{name}`")
                     };
                     let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
-                        format!("global paths cannot start with {}", name_str)
+                        format!("global paths cannot start with {name_str}")
                     } else {
-                        format!("{} in paths can only be used in start position", name_str)
+                        format!("{name_str} in paths can only be used in start position")
                     };
                     (label, None)
                 });
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index e1dae57d34f..a175d9f6c7f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -533,15 +533,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
 
         for (is_indeterminate, import) in determined_imports
-            .into_iter()
+            .iter()
             .map(|i| (false, i))
-            .chain(indeterminate_imports.into_iter().map(|i| (true, i)))
+            .chain(indeterminate_imports.iter().map(|i| (true, i)))
         {
-            let unresolved_import_error = self.finalize_import(import);
+            let unresolved_import_error = self.finalize_import(*import);
 
             // If this import is unresolved then create a dummy import
             // resolution for it so that later resolve stages won't complain.
-            self.import_dummy_binding(import, is_indeterminate);
+            self.import_dummy_binding(*import, is_indeterminate);
 
             if let Some(err) = unresolved_import_error {
                 if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
@@ -563,27 +563,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     errors = vec![];
                 }
                 if seen_spans.insert(err.span) {
-                    errors.push((import, err));
+                    errors.push((*import, err));
                     prev_root_id = import.root_id;
                 }
-            } else if is_indeterminate {
-                let path = import_path_to_string(
-                    &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
-                    &import.kind,
-                    import.span,
-                );
-                let err = UnresolvedImportError {
-                    span: import.span,
-                    label: None,
-                    note: None,
-                    suggestion: None,
-                    candidates: None,
-                };
-                // FIXME: there should be a better way of doing this than
-                // formatting this as a string then checking for `::`
-                if path.contains("::") {
-                    errors.push((import, err))
-                }
+            }
+        }
+
+        if !errors.is_empty() {
+            self.throw_unresolved_import_error(errors);
+            return;
+        }
+
+        for import in &indeterminate_imports {
+            let path = import_path_to_string(
+                &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+                &import.kind,
+                import.span,
+            );
+            let err = UnresolvedImportError {
+                span: import.span,
+                label: None,
+                note: None,
+                suggestion: None,
+                candidates: None,
+            };
+            // FIXME: there should be a better way of doing this than
+            // formatting this as a string then checking for `::`
+            if path.contains("::") {
+                errors.push((*import, err))
             }
         }
 
@@ -1153,18 +1160,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     ModuleOrUniformRoot::Module(module) => {
                         let module_str = module_to_string(module);
                         if let Some(module_str) = module_str {
-                            format!("no `{}` in `{}`", ident, module_str)
+                            format!("no `{ident}` in `{module_str}`")
                         } else {
-                            format!("no `{}` in the root", ident)
+                            format!("no `{ident}` in the root")
                         }
                     }
                     _ => {
                         if !ident.is_path_segment_keyword() {
-                            format!("no external crate `{}`", ident)
+                            format!("no external crate `{ident}`")
                         } else {
                             // HACK(eddyb) this shows up for `self` & `super`, which
                             // should work instead - for now keep the same error message.
-                            format!("no `{}` in the root", ident)
+                            format!("no `{ident}` in the root")
                         }
                     }
                 };
@@ -1212,10 +1219,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let (ns, binding) = reexport_error.unwrap();
             if pub_use_of_private_extern_crate_hack(import, binding) {
                 let msg = format!(
-                    "extern crate `{}` is private, and cannot be \
+                    "extern crate `{ident}` is private, and cannot be \
                                    re-exported (error E0365), consider declaring with \
-                                   `pub`",
-                    ident
+                                   `pub`"
                 );
                 self.lint_buffer.buffer_lint(
                     PUB_USE_OF_PRIVATE_EXTERN_CRATE,
@@ -1355,7 +1361,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 UNUSED_IMPORTS,
                 id,
                 import.span,
-                format!("the item `{}` is imported redundantly", ident),
+                format!("the item `{ident}` is imported redundantly"),
                 BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
             );
         }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6872b1b24a9..0e9d74480a9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1917,10 +1917,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         candidate: LifetimeElisionCandidate,
     ) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
-            panic!(
-                "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
-                id, prev_res, res
-            )
+            panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
         }
         match res {
             LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
@@ -1936,8 +1933,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!(
-                "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
-                id, prev_res, res
+                "lifetime parameter {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)"
             )
         }
     }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 072fa864f4e..974580f815b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -585,13 +585,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     let others = match enum_candidates.len() {
                         1 => String::new(),
                         2 => " and 1 other".to_owned(),
-                        n => format!(" and {} others", n),
+                        n => format!(" and {n} others"),
                     };
                     format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
                 } else {
                     String::new()
                 };
-                let msg = format!("{}try using the variant's enum", preamble);
+                let msg = format!("{preamble}try using the variant's enum");
 
                 err.span_suggestions(
                     span,
@@ -696,7 +696,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     ident.name == path[0].ident.name {
                     err.span_help(
                         ident.span,
-                        format!("the binding `{}` is available in a different scope in the same function", path_str),
+                        format!("the binding `{path_str}` is available in a different scope in the same function"),
                     );
                     return (true, candidates);
                 }
@@ -858,7 +858,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 for label_rib in &self.label_ribs {
                     for (label_ident, node_id) in &label_rib.bindings {
                         let ident = path.last().unwrap().ident;
-                        if format!("'{}", ident) == label_ident.to_string() {
+                        if format!("'{ident}") == label_ident.to_string() {
                             err.span_label(label_ident.span, "a label with a similar name exists");
                             if let PathSource::Expr(Some(Expr {
                                 kind: ExprKind::Break(None, Some(_)),
@@ -983,7 +983,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 if let Some(ident) = fn_kind.ident() {
                     err.span_label(
                         ident.span,
-                        format!("this function {} have a `self` parameter", doesnt),
+                        format!("this function {doesnt} have a `self` parameter"),
                     );
                 }
             }
@@ -1164,7 +1164,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         };
                         err.span_suggestion_verbose(
                             *where_span,
-                            format!("constrain the associated type to `{}`", ident),
+                            format!("constrain the associated type to `{ident}`"),
                             where_bound_predicate_to_string(&new_where_bound_predicate),
                             Applicability::MaybeIncorrect,
                         );
@@ -1338,8 +1338,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             span, // Note the parentheses surrounding the suggestion below
                             format!(
                                 "you might want to surround a struct literal with parentheses: \
-                                 `({} {{ /* fields */ }})`?",
-                                path_str
+                                 `({path_str} {{ /* fields */ }})`?"
                             ),
                         );
                     }
@@ -1373,7 +1372,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                                     .map(|(idx, new)| (new, old_fields.get(idx)))
                                     .map(|(new, old)| {
                                         let new = new.to_ident_string();
-                                        if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new }
+                                        if let Some(Some(old)) = old && new != *old { format!("{new}: {old}") } else { new }
                                     })
                                     .collect::<Vec<String>>()
                             } else {
@@ -1390,7 +1389,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     };
                     err.span_suggestion(
                         span,
-                        format!("use struct {} syntax instead", descr),
+                        format!("use struct {descr} syntax instead"),
                         format!("{path_str} {{{pad}{fields}{pad}}}"),
                         applicability,
                     );
@@ -1584,7 +1583,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 err.span_suggestion(
                     span,
                     "use the tuple variant pattern syntax instead",
-                    format!("{}({})", path_str, fields),
+                    format!("{path_str}({fields})"),
                     Applicability::HasPlaceholders,
                 );
             }
@@ -1994,9 +1993,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
             if !suggestable_variants.is_empty() {
                 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
-                    format!("try {} the enum's variant", source_msg)
+                    format!("try {source_msg} the enum's variant")
                 } else {
-                    format!("try {} one of the enum's variants", source_msg)
+                    format!("try {source_msg} one of the enum's variants")
                 };
 
                 err.span_suggestions(
@@ -2009,19 +2008,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
             // If the enum has no tuple variants..
             if non_suggestable_variant_count == variants.len() {
-                err.help(format!("the enum has no tuple variants {}", source_msg));
+                err.help(format!("the enum has no tuple variants {source_msg}"));
             }
 
             // If there are also non-tuple variants..
             if non_suggestable_variant_count == 1 {
-                err.help(format!(
-                    "you might have meant {} the enum's non-tuple variant",
-                    source_msg
-                ));
+                err.help(format!("you might have meant {source_msg} the enum's non-tuple variant"));
             } else if non_suggestable_variant_count >= 1 {
                 err.help(format!(
-                    "you might have meant {} one of the enum's non-tuple variants",
-                    source_msg
+                    "you might have meant {source_msg} one of the enum's non-tuple variants"
                 ));
             }
         } else {
@@ -2041,7 +2036,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
                 .map(|(variant, kind)| match kind {
                     CtorKind::Const => variant,
-                    CtorKind::Fn => format!("({}())", variant),
+                    CtorKind::Fn => format!("({variant}())"),
                 })
                 .collect::<Vec<_>>();
             let no_suggestable_variant = suggestable_variants.is_empty();
@@ -2066,7 +2061,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
                 .filter_map(|(variant, kind)| match kind {
-                    CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
+                    CtorKind::Fn => Some(format!("({variant}(/* fields */))")),
                     _ => None,
                 })
                 .collect::<Vec<_>>();
@@ -2361,8 +2356,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         err.span_label(
                             span,
                             format!(
-                                "lifetime `{}` is missing in item created through this procedural macro",
-                                name,
+                                "lifetime `{name}` is missing in item created through this procedural macro",
                             ),
                         );
                         continue;
@@ -2406,7 +2400,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         );
                     } else if let Some(name) = name {
                         let message =
-                            Cow::from(format!("consider introducing lifetime `{}` here", name));
+                            Cow::from(format!("consider introducing lifetime `{name}` here"));
                         should_continue = suggest(err, false, span, message, sugg);
                     } else {
                         let message = Cow::from("consider introducing a named lifetime parameter");
@@ -2550,7 +2544,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
 
                 let help_name = if let Some(ident) = ident {
-                    format!("`{}`", ident)
+                    format!("`{ident}`")
                 } else {
                     format!("argument {}", index + 1)
                 };
@@ -2558,7 +2552,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 if lifetime_count == 1 {
                     m.push_str(&help_name[..])
                 } else {
-                    m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+                    m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..])
                 }
             }
 
@@ -2588,14 +2582,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             } else if num_params == 1 {
                 err.help(format!(
                     "this function's return type contains a borrowed value, \
-                 but the signature does not say which {} it is borrowed from",
-                    m
+                 but the signature does not say which {m} it is borrowed from"
                 ));
             } else {
                 err.help(format!(
                     "this function's return type contains a borrowed value, \
-                 but the signature does not say whether it is borrowed from {}",
-                    m
+                 but the signature does not say whether it is borrowed from {m}"
                 ));
             }
         }
@@ -2614,7 +2606,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
             MissingLifetimeKind::Ampersand => {
                 debug_assert_eq!(lt.count, 1);
-                (lt.span.shrink_to_hi(), format!("{} ", existing_name))
+                (lt.span.shrink_to_hi(), format!("{existing_name} "))
             }
             MissingLifetimeKind::Comma => {
                 let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
@@ -2661,7 +2653,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
             1 => {
                 err.multipart_suggestion_verbose(
-                    format!("consider using the `{}` lifetime", existing_name),
+                    format!("consider using the `{existing_name}` lifetime"),
                     spans_suggs,
                     Applicability::MaybeIncorrect,
                 );
@@ -2778,9 +2770,9 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident
     let shadower = shadower.span;
     let mut err = sess.struct_span_warn(
         shadower,
-        format!("label name `{}` shadows a label name that is already in scope", name),
+        format!("label name `{name}` shadows a label name that is already in scope"),
     );
     err.span_label(orig, "first declared here");
-    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.span_label(shadower, format!("label `{name}` already in scope"));
     err.emit();
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 91d89f44dbf..da5e92a075a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
     /// Adds a definition with a parent definition.
@@ -1834,7 +1834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         debug!("(recording res) recording {:?} for {}", resolution, node_id);
         if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
-            panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution);
+            panic!("path resolved multiple times ({prev_res:?} before, {resolution:?} now)");
         }
     }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d456cc9a9a0..614a29e7578 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -207,7 +207,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
             self.tcx
                 .sess
                 .diagnostic()
-                .bug(format!("built-in macro `{}` was already registered", name));
+                .bug(format!("built-in macro `{name}` was already registered"));
         }
     }
 
@@ -570,7 +570,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             let mut err = self.tcx.sess.create_err(err);
-            err.span_label(path.span, format!("not {} {}", article, expected));
+            err.span_label(path.span, format!("not {article} {expected}"));
 
             err.emit();
 
@@ -906,7 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                 self.tcx.sess.span_err(
                     ident.span,
-                    format!("name `{}` is reserved in attribute namespace", ident),
+                    format!("name `{ident}` is reserved in attribute namespace"),
                 );
             }
         }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 88bbadefe26..28ae88424ab 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1539,9 +1539,8 @@ pub(super) fn build_target_config(
     );
     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
         handler.early_error(format!(
-            "Error loading target specification: {}. \
-                 Run `rustc --print target-list` for a list of built-in targets",
-            e
+            "Error loading target specification: {e}. \
+                 Run `rustc --print target-list` for a list of built-in targets"
         ))
     });
     for warning in target_warnings.warning_messages() {
@@ -1978,8 +1977,7 @@ pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Match
         let is_nightly = nightly_options::match_is_nightly_build(matches);
         let msg = if !is_nightly {
             format!(
-                "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
-                edition, LATEST_STABLE_EDITION
+                "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
             )
         } else {
             format!("edition {edition} is unstable and only available with -Z unstable-options")
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 4a535f80b8a..055ab2d9c15 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -330,8 +330,7 @@ fn build_options<O: Default>(
                     match value {
                         None => handler.early_error(
                             format!(
-                                "{0} option `{1}` requires {2} ({3} {1}=<value>)",
-                                outputname, key, type_desc, prefix
+                                "{outputname} option `{key}` requires {type_desc} ({prefix} {key}=<value>)"
                             ),
                         ),
                         Some(value) => handler.early_error(
@@ -1882,6 +1881,7 @@ written to standard error output)"),
 
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
+    // - src/doc/unstable-book/src/compiler-flags
 }
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 0a33030c603..c4bdec0ee28 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -8,11 +8,13 @@
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
 use crate::rustc_internal::{self, opaque};
+use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx};
 use crate::stable_mir::ty::{FloatTy, IntTy, Movability, RigidTy, TyKind, UintTy};
 use crate::stable_mir::{self, Context};
 use rustc_hir as hir;
-use rustc_middle::mir;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::mir::coverage::CodeRegion;
+use rustc_middle::mir::{self};
+use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_target::abi::FieldIdx;
 use tracing::debug;
@@ -110,17 +112,38 @@ impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
             Assign(assign) => {
                 stable_mir::mir::Statement::Assign(assign.0.stable(tables), assign.1.stable(tables))
             }
-            FakeRead(_) => todo!(),
-            SetDiscriminant { .. } => todo!(),
-            Deinit(_) => todo!(),
-            StorageLive(_) => todo!(),
-            StorageDead(_) => todo!(),
-            Retag(_, _) => todo!(),
-            PlaceMention(_) => todo!(),
-            AscribeUserType(_, _) => todo!(),
-            Coverage(_) => todo!(),
-            Intrinsic(_) => todo!(),
-            ConstEvalCounter => todo!(),
+            FakeRead(fake_read_place) => stable_mir::mir::Statement::FakeRead(
+                fake_read_place.0.stable(tables),
+                fake_read_place.1.stable(tables),
+            ),
+            SetDiscriminant { place: plc, variant_index: idx } => {
+                stable_mir::mir::Statement::SetDiscriminant {
+                    place: plc.as_ref().stable(tables),
+                    variant_index: idx.stable(tables),
+                }
+            }
+            Deinit(place) => stable_mir::mir::Statement::Deinit(place.stable(tables)),
+            StorageLive(place) => stable_mir::mir::Statement::StorageLive(place.stable(tables)),
+            StorageDead(place) => stable_mir::mir::Statement::StorageDead(place.stable(tables)),
+            Retag(retag, place) => {
+                stable_mir::mir::Statement::Retag(retag.stable(tables), place.stable(tables))
+            }
+            PlaceMention(place) => stable_mir::mir::Statement::PlaceMention(place.stable(tables)),
+            AscribeUserType(place_projection, variance) => {
+                stable_mir::mir::Statement::AscribeUserType {
+                    place: place_projection.as_ref().0.stable(tables),
+                    projections: place_projection.as_ref().1.stable(tables),
+                    variance: variance.stable(tables),
+                }
+            }
+            Coverage(coverage) => stable_mir::mir::Statement::Coverage(stable_mir::mir::Coverage {
+                kind: coverage.kind.stable(tables),
+                code_region: coverage.code_region.as_ref().map(|reg| reg.stable(tables)),
+            }),
+            Intrinsic(intrinstic) => {
+                stable_mir::mir::Statement::Intrinsic(intrinstic.stable(tables))
+            }
+            ConstEvalCounter => stable_mir::mir::Statement::ConstEvalCounter,
             Nop => stable_mir::mir::Statement::Nop,
         }
     }
@@ -132,7 +155,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
         use mir::Rvalue::*;
         match self {
             Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)),
-            Repeat(_, _) => todo!(),
+            Repeat(op, len) => stable_mir::mir::Rvalue::Repeat(op.stable(tables), opaque(len)),
             Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref(
                 opaque(region),
                 kind.stable(tables),
@@ -145,7 +168,11 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
             }
             Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
-            Cast(_, _, _) => todo!(),
+            Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
+                cast_kind.stable(tables),
+                op.stable(tables),
+                tables.intern_ty(*ty),
+            ),
             BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
                 bin_op.stable(tables),
                 ops.0.stable(tables),
@@ -163,8 +190,13 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
             }
             Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)),
-            Aggregate(_, _) => todo!(),
-            ShallowInitBox(_, _) => todo!(),
+            Aggregate(agg_kind, operands) => {
+                let operands = operands.iter().map(|op| op.stable(tables)).collect();
+                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
+            }
+            ShallowInitBox(op, ty) => {
+                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), tables.intern_ty(*ty))
+            }
             CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
         }
     }
@@ -355,6 +387,22 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
     }
 }
 
+impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
+    type T = stable_mir::mir::FakeReadCause;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use mir::FakeReadCause::*;
+        match self {
+            ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
+            ForMatchedPlace(local_def_id) => {
+                stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id))
+            }
+            ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding,
+            ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)),
+            ForIndex => stable_mir::mir::FakeReadCause::ForIndex,
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for FieldIdx {
     type T = usize;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -384,6 +432,110 @@ impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
     }
 }
 
+impl<'tcx> Stable<'tcx> for mir::coverage::CoverageKind {
+    type T = stable_mir::mir::CoverageKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::coverage::CoverageKind;
+        match self {
+            CoverageKind::Counter { function_source_hash, id } => {
+                stable_mir::mir::CoverageKind::Counter {
+                    function_source_hash: *function_source_hash as usize,
+                    id: opaque(id),
+                }
+            }
+            CoverageKind::Expression { id, lhs, op, rhs } => {
+                stable_mir::mir::CoverageKind::Expression {
+                    id: opaque(id),
+                    lhs: opaque(lhs),
+                    op: op.stable(tables),
+                    rhs: opaque(rhs),
+                }
+            }
+            CoverageKind::Unreachable => stable_mir::mir::CoverageKind::Unreachable,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
+    type T = stable_mir::mir::UserTypeProjection;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::coverage::Op {
+    type T = stable_mir::mir::Op;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::coverage::Op::*;
+        match self {
+            Subtract => stable_mir::mir::Op::Subtract,
+            Add => stable_mir::mir::Op::Add,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Local {
+    type T = stable_mir::mir::Local;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+    type T = VariantIdx;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for Variance {
+    type T = stable_mir::mir::Variance;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Variance::Bivariant => stable_mir::mir::Variance::Bivariant,
+            Variance::Contravariant => stable_mir::mir::Variance::Contravariant,
+            Variance::Covariant => stable_mir::mir::Variance::Covariant,
+            Variance::Invariant => stable_mir::mir::Variance::Invariant,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::RetagKind {
+    type T = stable_mir::mir::RetagKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::RetagKind;
+        match self {
+            RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
+            RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase,
+            RetagKind::Raw => stable_mir::mir::RetagKind::Raw,
+            RetagKind::Default => stable_mir::mir::RetagKind::Default,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::UserTypeAnnotationIndex {
+    type T = usize;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for CodeRegion {
+    type T = stable_mir::mir::CodeRegion;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::CodeRegion {
+            file_name: self.file_name.as_str().to_string(),
+            start_line: self.start_line as usize,
+            start_col: self.start_col as usize,
+            end_line: self.end_line as usize,
+            end_col: self.end_col as usize,
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for mir::UnwindAction {
     type T = stable_mir::mir::UnwindAction;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -397,6 +549,26 @@ impl<'tcx> Stable<'tcx> for mir::UnwindAction {
     }
 }
 
+impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
+    type T = stable_mir::mir::NonDivergingIntrinsic;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::NonDivergingIntrinsic;
+        match self {
+            NonDivergingIntrinsic::Assume(op) => {
+                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
+                stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+                    src: copy_non_overlapping.src.stable(tables),
+                    dst: copy_non_overlapping.dst.stable(tables),
+                    count: copy_non_overlapping.count.stable(tables),
+                })
+            }
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
     type T = stable_mir::mir::AssertMessage;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
@@ -478,6 +650,40 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
     }
 }
 
+impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
+    type T = stable_mir::mir::AggregateKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            mir::AggregateKind::Array(ty) => {
+                stable_mir::mir::AggregateKind::Array(tables.intern_ty(*ty))
+            }
+            mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
+            mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
+                stable_mir::mir::AggregateKind::Adt(
+                    rustc_internal::adt_def(*def_id),
+                    var_idx.index(),
+                    generic_arg.stable(tables),
+                    user_ty_index.map(|idx| idx.index()),
+                    field_idx.map(|idx| idx.index()),
+                )
+            }
+            mir::AggregateKind::Closure(def_id, generic_arg) => {
+                stable_mir::mir::AggregateKind::Closure(
+                    rustc_internal::closure_def(*def_id),
+                    generic_arg.stable(tables),
+                )
+            }
+            mir::AggregateKind::Generator(def_id, generic_arg, movability) => {
+                stable_mir::mir::AggregateKind::Generator(
+                    rustc_internal::generator_def(*def_id),
+                    generic_arg.stable(tables),
+                    movability.stable(tables),
+                )
+            }
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for rustc_hir::GeneratorKind {
     type T = stable_mir::mir::GeneratorKind;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -512,7 +718,7 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
             | InlineAsmOperand::SymStatic { .. } => (None, None),
         };
 
-        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", self) }
+        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") }
     }
 }
 
@@ -561,10 +767,10 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
             },
             InlineAsm { template, operands, options, line_spans, destination, unwind } => {
                 Terminator::InlineAsm {
-                    template: format!("{:?}", template),
+                    template: format!("{template:?}"),
                     operands: operands.iter().map(|operand| operand.stable(tables)).collect(),
-                    options: format!("{:?}", options),
-                    line_spans: format!("{:?}", line_spans),
+                    options: format!("{options:?}"),
+                    line_spans: format!("{line_spans:?}"),
                     destination: destination.map(|d| d.as_usize()),
                     unwind: unwind.stable(tables),
                 }
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
index 1b1871bcd2a..c16bd6cbd70 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/body.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -1,4 +1,7 @@
-use crate::stable_mir::ty::Region;
+use crate::rustc_internal::Opaque;
+use crate::stable_mir::ty::{
+    AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region,
+};
 use crate::stable_mir::{self, ty::Ty};
 
 #[derive(Clone, Debug)]
@@ -131,13 +134,104 @@ pub enum AsyncGeneratorKind {
     Fn,
 }
 
+pub(crate) type LocalDefId = Opaque;
+pub(crate) type CounterValueReference = Opaque;
+pub(crate) type InjectedExpressionId = Opaque;
+pub(crate) type ExpressionOperandId = Opaque;
+
+/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
+#[derive(Clone, Debug)]
+pub enum FakeReadCause {
+    ForMatchGuard,
+    ForMatchedPlace(LocalDefId),
+    ForGuardBinding,
+    ForLet(LocalDefId),
+    ForIndex,
+}
+
+/// Describes what kind of retag is to be performed
+#[derive(Clone, Debug)]
+pub enum RetagKind {
+    FnEntry,
+    TwoPhase,
+    Raw,
+    Default,
+}
+
+#[derive(Clone, Debug)]
+pub enum Variance {
+    Covariant,
+    Invariant,
+    Contravariant,
+    Bivariant,
+}
+
+#[derive(Clone, Debug)]
+pub enum Op {
+    Subtract,
+    Add,
+}
+
+#[derive(Clone, Debug)]
+pub enum CoverageKind {
+    Counter {
+        function_source_hash: usize,
+        id: CounterValueReference,
+    },
+    Expression {
+        id: InjectedExpressionId,
+        lhs: ExpressionOperandId,
+        op: Op,
+        rhs: ExpressionOperandId,
+    },
+    Unreachable,
+}
+
+#[derive(Clone, Debug)]
+pub struct CodeRegion {
+    pub file_name: String,
+    pub start_line: usize,
+    pub start_col: usize,
+    pub end_line: usize,
+    pub end_col: usize,
+}
+
+#[derive(Clone, Debug)]
+pub struct Coverage {
+    pub kind: CoverageKind,
+    pub code_region: Option<CodeRegion>,
+}
+
+#[derive(Clone, Debug)]
+pub struct CopyNonOverlapping {
+    pub src: Operand,
+    pub dst: Operand,
+    pub count: Operand,
+}
+
+#[derive(Clone, Debug)]
+pub enum NonDivergingIntrinsic {
+    Assume(Operand),
+    CopyNonOverlapping(CopyNonOverlapping),
+}
+
 #[derive(Clone, Debug)]
 pub enum Statement {
     Assign(Place, Rvalue),
+    FakeRead(FakeReadCause, Place),
+    SetDiscriminant { place: Place, variant_index: VariantIdx },
+    Deinit(Place),
+    StorageLive(Local),
+    StorageDead(Local),
+    Retag(RetagKind, Place),
+    PlaceMention(Place),
+    AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
+    Coverage(Coverage),
+    Intrinsic(NonDivergingIntrinsic),
+    ConstEvalCounter,
     Nop,
 }
 
-// FIXME this is incomplete
 #[derive(Clone, Debug)]
 pub enum Rvalue {
     /// Creates a pointer with the indicated mutability to the place.
@@ -146,6 +240,16 @@ pub enum Rvalue {
     /// `&raw v` or `addr_of!(v)`.
     AddressOf(Mutability, Place),
 
+    /// Creates an aggregate value, like a tuple or struct.
+    ///
+    /// This is needed because dataflow analysis needs to distinguish
+    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
+    /// has a destructor.
+    ///
+    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
+    /// generator lowering, `Generator` aggregate kinds are disallowed too.
+    Aggregate(AggregateKind, Vec<Operand>),
+
     /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
     ///   parameter may be a `usize` as well.
     /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
@@ -198,6 +302,16 @@ pub enum Rvalue {
     /// Creates a reference to the place.
     Ref(Region, BorrowKind, Place),
 
+    /// Creates an array where each element is the value of the operand.
+    ///
+    /// This is the cause of a bug in the case where the repetition count is zero because the value
+    /// is not dropped, see [#74836].
+    ///
+    /// Corresponds to source code like `[x; 32]`.
+    ///
+    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
+    Repeat(Operand, Const),
+
     /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
     ///
     /// This is different from a normal transmute because dataflow analysis will treat the box as
@@ -233,6 +347,15 @@ pub enum Rvalue {
 }
 
 #[derive(Clone, Debug)]
+pub enum AggregateKind {
+    Array(Ty),
+    Tuple,
+    Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
+    Closure(ClosureDef, GenericArgs),
+    Generator(GeneratorDef, GenericArgs, Movability),
+}
+
+#[derive(Clone, Debug)]
 pub enum Operand {
     Copy(Place),
     Move(Place),
@@ -241,12 +364,25 @@ pub enum Operand {
 
 #[derive(Clone, Debug)]
 pub struct Place {
-    pub local: usize,
+    pub local: Local,
+    pub projection: String,
+}
+
+#[derive(Clone, Debug)]
+pub struct UserTypeProjection {
+    pub base: UserTypeAnnotationIndex,
     pub projection: String,
 }
 
+pub type Local = usize;
+
 type FieldIdx = usize;
 
+/// The source-order index of a variant in a type.
+pub type VariantIdx = usize;
+
+type UserTypeAnnotationIndex = usize;
+
 #[derive(Clone, Debug)]
 pub struct SwitchTarget {
     pub value: u128,
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 7a72afd666c..025225b8d19 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -10,7 +10,7 @@ impl Ty {
     }
 }
 
-type Const = Opaque;
+pub(crate) type Const = Opaque;
 pub(crate) type Region = Opaque;
 type Span = Opaque;
 
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index ecaa82874a3..fbd9bf05528 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -605,7 +605,7 @@ impl Span {
         // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
         // the callsite span and the span will be pointing at different places. It also means that
         // we can safely provide suggestions on this span.
-            || (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
+            || (self.in_derive_expansion()
                 && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8122fe96a5c..d3739733c1d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1371,9 +1371,13 @@ symbols! {
         simd_arith_offset,
         simd_as,
         simd_bitmask,
+        simd_bitreverse,
+        simd_bswap,
         simd_cast,
         simd_cast_ptr,
         simd_ceil,
+        simd_ctlz,
+        simd_cttz,
         simd_div,
         simd_eq,
         simd_expose_addr,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index a4a9c0aa0dd..c215a7c4b6e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1300,6 +1300,7 @@ supported_targets! {
     ("armv7-linux-androideabi", armv7_linux_androideabi),
     ("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi),
     ("aarch64-linux-android", aarch64_linux_android),
+    ("riscv64-linux-android", riscv64_linux_android),
 
     ("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
     ("armv6-unknown-freebsd", armv6_unknown_freebsd),
diff --git a/compiler/rustc_target/src/spec/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/riscv64_linux_android.rs
new file mode 100644
index 00000000000..af0d6855494
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv64_linux_android.rs
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv64-linux-android".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
+        arch: "riscv64".into(),
+        options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv64".into(),
+            features: "+m,+a,+f,+d,+c".into(),
+            llvm_abiname: "lp64d".into(),
+            supported_sanitizers: SanitizerSet::ADDRESS,
+            max_atomic_width: Some(64),
+            ..super::android_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index ab90db6ff58..5ec48c7ac57 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::inspect::CandidateKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -299,7 +299,7 @@ pub(super) trait GoalKind<'tcx>:
     /// for unsize coercion in hir typeck and because it is difficult to
     /// otherwise recompute this for codegen. This is a bit of a mess but the
     /// easiest way to maintain the existing behavior for now.
-    fn consider_builtin_unsize_and_upcast_candidates(
+    fn consider_builtin_unsize_candidates(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
@@ -402,7 +402,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 ecx.with_incremented_depth(
                     |ecx| {
                         let result = ecx.evaluate_added_goals_and_make_canonical_response(
-                            Certainty::Maybe(MaybeCause::Overflow),
+                            Certainty::OVERFLOW,
                         )?;
                         Ok(vec![Candidate {
                             source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
@@ -624,7 +624,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // There may be multiple unsize candidates for a trait with several supertraits:
         // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
         if lang_items.unsize_trait() == Some(trait_def_id) {
-            for (result, source) in G::consider_builtin_unsize_and_upcast_candidates(self, goal) {
+            for (result, source) in G::consider_builtin_unsize_candidates(self, goal) {
                 candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result });
             }
         }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 9e3b0bbc4fb..485bc912c44 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -11,8 +11,8 @@ use rustc_infer::traits::ObligationCause;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::solve::inspect;
 use rustc_middle::traits::solve::{
-    CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause,
-    PredefinedOpaques, PredefinedOpaquesData, QueryResult,
+    CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques,
+    PredefinedOpaquesData, QueryResult,
 };
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::{
@@ -475,7 +475,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let mut new_goals = NestedGoals::new();
 
         let response = self.repeat_while_none(
-            |_| Ok(Certainty::Maybe(MaybeCause::Overflow)),
+            |_| Ok(Certainty::OVERFLOW),
             |this| {
                 this.inspect.evaluate_added_goals_loop_start();
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 6045001510e..1aef9a885bc 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -100,10 +100,18 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
                 rematch_impl(self, goal, def_id, nested_obligations)
             }
 
+            // If an unsize goal is ambiguous, then we can manually rematch it to make
+            // selection progress for coercion during HIR typeck. If it is *not* ambiguous,
+            // but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
+            // and we need to rematch those to detect tuple unsizing and trait upcasting.
+            // FIXME: This will be wrong if we have param-env or where-clause bounds
+            // with the unsize goal -- we may need to mark those with different impl
+            // sources.
             (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
+            | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
                 if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
             {
-                rematch_unsize(self, goal, nested_obligations, src)
+                rematch_unsize(self, goal, nested_obligations, src, certainty)
             }
 
             // Technically some builtin impls have nested obligations, but if
@@ -217,6 +225,7 @@ fn rematch_unsize<'tcx>(
     goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
     mut nested: Vec<PredicateObligation<'tcx>>,
     source: BuiltinImplSource,
+    certainty: Certainty,
 ) -> SelectionResult<'tcx, Selection<'tcx>> {
     let tcx = infcx.tcx;
     let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
@@ -227,6 +236,12 @@ fn rematch_unsize<'tcx>(
         &mut nested,
     );
     match (a_ty.kind(), b_ty.kind()) {
+        // Stall any ambiguous upcasting goals, since we can't rematch those
+        (ty::Dynamic(_, _, ty::Dyn), ty::Dynamic(_, _, ty::Dyn)) => match certainty {
+            Certainty::Yes => Ok(Some(ImplSource::Builtin(source, nested))),
+            _ => Ok(None),
+        },
+        // `T` -> `dyn Trait` upcasting
         (_, &ty::Dynamic(data, region, ty::Dyn)) => {
             // Check that the type implements all of the predicates of the def-id.
             // (i.e. the principal, all of the associated types match, and any auto traits)
@@ -338,7 +353,7 @@ fn rematch_unsize<'tcx>(
                     .into_obligations(),
             );
 
-            // Similar to ADTs, require that the rest of the fields are equal.
+            // Similar to ADTs, require that we can unsize the tail.
             nested.push(Obligation::new(
                 tcx,
                 ObligationCause::dummy(),
@@ -354,10 +369,10 @@ fn rematch_unsize<'tcx>(
             );
             Ok(Some(ImplSource::Builtin(source, nested)))
         }
-        // FIXME: We *could* ICE here if either:
-        // 1. the certainty is `Certainty::Yes`,
-        // 2. we're in codegen (which should mean `Certainty::Yes`).
-        _ => Ok(None),
+        _ => {
+            assert_ne!(certainty, Certainty::Yes);
+            Ok(None)
+        }
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 03ade738bb6..2ce57751740 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -503,7 +503,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         )
     }
 
-    fn consider_builtin_unsize_and_upcast_candidates(
+    fn consider_builtin_unsize_candidates(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 98c8a74752c..c25d6eca918 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -9,9 +9,7 @@ use cache::ProvisionalCache;
 use overflow::OverflowData;
 use rustc_index::IndexVec;
 use rustc_middle::dep_graph::DepKind;
-use rustc_middle::traits::solve::{
-    CanonicalInput, Certainty, EvaluationCache, MaybeCause, QueryResult,
-};
+use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
 use rustc_middle::ty::TyCtxt;
 use std::{collections::hash_map::Entry, mem};
 
@@ -146,11 +144,7 @@ impl<'tcx> SearchGraph<'tcx> {
                 {
                     Err(cache.provisional_result(entry_index))
                 } else {
-                    Err(super::response_no_constraints(
-                        tcx,
-                        input,
-                        Certainty::Maybe(MaybeCause::Overflow),
-                    ))
+                    Err(super::response_no_constraints(tcx, input, Certainty::OVERFLOW))
                 }
             }
         }
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
index e0a2e0c5cc2..83a051eeb1a 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
@@ -1,6 +1,6 @@
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::traits::solve::{Certainty, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{Certainty, QueryResult};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Limit;
 
@@ -115,6 +115,6 @@ impl<'tcx> SearchGraph<'tcx> {
         goal: Canonical<'tcx, impl Sized>,
     ) -> QueryResult<'tcx> {
         self.overflow_data.deal_with_overflow();
-        response_no_constraints(tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
+        response_no_constraints(tcx, goal, Certainty::OVERFLOW)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 40ce4a3b3e4..14a5b9656e5 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::inspect::CandidateKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
 use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -366,69 +366,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         )
     }
 
-    fn consider_builtin_unsize_and_upcast_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return vec![];
-        }
-
-        ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
-            let a_ty = goal.predicate.self_ty();
-            // We need to normalize the b_ty since it's matched structurally
-            // in the other functions below.
-            let b_ty = match ecx
-                .normalize_non_self_ty(goal.predicate.trait_ref.args.type_at(1), goal.param_env)
-            {
-                Ok(Some(b_ty)) => {
-                    // If we have a type var, then bail with ambiguity.
-                    if b_ty.is_ty_var() {
-                        return vec![(
-                            ecx.evaluate_added_goals_and_make_canonical_response(
-                                Certainty::AMBIGUOUS,
-                            )
-                            .unwrap(),
-                            BuiltinImplSource::Misc,
-                        )];
-                    } else {
-                        b_ty
-                    }
-                }
-                Ok(None) => {
-                    return vec![(
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
-                            MaybeCause::Overflow,
-                        ))
-                        .unwrap(),
-                        BuiltinImplSource::Misc,
-                    )];
-                }
-                Err(_) => return vec![],
-            };
-
-            let mut results = vec![];
-            results.extend(ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty));
-            results.extend(
-                ecx.consider_builtin_unsize_candidate(goal.with(ecx.tcx(), (a_ty, b_ty)))
-                    .into_iter()
-                    .map(|resp| {
-                        // If we're unsizing from tuple -> tuple, detect
-                        let source =
-                            if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..)))
-                            {
-                                BuiltinImplSource::TupleUnsizing
-                            } else {
-                                BuiltinImplSource::Misc
-                            };
-                        (resp, source)
-                    }),
-            );
-
-            results
-        })
-    }
-
     fn consider_builtin_discriminant_kind_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -486,153 +423,111 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         )?;
         ecx.evaluate_added_goals_and_make_canonical_response(certainty)
     }
-}
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    fn consider_builtin_unsize_candidate(
-        &mut self,
-        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
-    ) -> QueryResult<'tcx> {
-        let Goal { param_env, predicate: (a_ty, b_ty) } = goal;
-        self.probe_candidate("builtin unsize").enter(|ecx| {
-            let tcx = ecx.tcx();
+    fn consider_builtin_unsize_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return vec![];
+        }
+
+        let misc_candidate = |ecx: &mut EvalCtxt<'_, 'tcx>, certainty| {
+            (
+                ecx.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(),
+                BuiltinImplSource::Misc,
+            )
+        };
+
+        let result_to_single = |result, source| match result {
+            Ok(resp) => vec![(resp, source)],
+            Err(NoSolution) => vec![],
+        };
+
+        ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
+            let a_ty = goal.predicate.self_ty();
+            // We need to normalize the b_ty since it's matched structurally
+            // in the other functions below.
+            let b_ty = match ecx
+                .normalize_non_self_ty(goal.predicate.trait_ref.args.type_at(1), goal.param_env)
+            {
+                Ok(Some(b_ty)) => b_ty,
+                Ok(None) => return vec![misc_candidate(ecx, Certainty::OVERFLOW)],
+                Err(_) => return vec![],
+            };
+
+            let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
             match (a_ty.kind(), b_ty.kind()) {
-                (ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => {
-                    bug!("unexpected type variable in unsize goal")
-                }
-                // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
-                (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
-                    // Dyn upcasting is handled separately, since due to upcasting,
-                    // when there are two supertraits that differ by args, we
-                    // may return more than one query response.
-                    Err(NoSolution)
-                }
-                // `T` -> `dyn Trait` unsizing
-                (_, &ty::Dynamic(data, region, ty::Dyn)) => {
-                    // Can only unsize to an object-safe type
-                    if data
-                        .principal_def_id()
-                        .is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
-                    {
-                        return Err(NoSolution);
-                    }
+                (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
+                (_, ty::Infer(ty::TyVar(..))) => vec![misc_candidate(ecx, Certainty::AMBIGUOUS)],
 
-                    let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
-                        return Err(NoSolution);
-                    };
-                    // Check that the type implements all of the predicates of the def-id.
-                    // (i.e. the principal, all of the associated types match, and any auto traits)
-                    ecx.add_goals(
-                        data.iter()
-                            .map(|pred| Goal::new(tcx, param_env, pred.with_self_ty(tcx, a_ty))),
-                    );
-                    // The type must be Sized to be unsized.
-                    ecx.add_goal(Goal::new(
-                        tcx,
-                        param_env,
-                        ty::TraitRef::new(tcx, sized_def_id, [a_ty]),
-                    ));
-                    // The type must outlive the lifetime of the `dyn` we're unsizing into.
-                    ecx.add_goal(Goal::new(
-                        tcx,
-                        param_env,
-                        ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
-                    ));
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }
-                // `[T; n]` -> `[T]` unsizing
-                (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
-                    // We just require that the element type stays the same
-                    ecx.eq(param_env, a_elem_ty, b_elem_ty)?;
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }
-                // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
+                // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
+                (
+                    &ty::Dynamic(a_data, a_region, ty::Dyn),
+                    &ty::Dynamic(b_data, b_region, ty::Dyn),
+                ) => ecx.consider_builtin_dyn_upcast_candidates(
+                    goal, a_data, a_region, b_data, b_region,
+                ),
+
+                // `T` -> `dyn Trait` unsizing
+                (_, &ty::Dynamic(b_data, b_region, ty::Dyn)) => result_to_single(
+                    ecx.consider_builtin_unsize_to_dyn(goal, b_data, b_region),
+                    BuiltinImplSource::Misc,
+                ),
+
+                // `[T; N]` -> `[T]` unsizing
+                (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single(
+                    ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty),
+                    BuiltinImplSource::Misc,
+                ),
+
+                // `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
                 (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
-                    if a_def.is_struct() && a_def.did() == b_def.did() =>
+                    if a_def.is_struct() && a_def == b_def =>
                 {
-                    let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
-                    // We must be unsizing some type parameters. This also implies
-                    // that the struct has a tail field.
-                    if unsizing_params.is_empty() {
-                        return Err(NoSolution);
-                    }
-
-                    let tail_field = a_def.non_enum_variant().tail();
-                    let tail_field_ty = tcx.type_of(tail_field.did);
-
-                    let a_tail_ty = tail_field_ty.instantiate(tcx, a_args);
-                    let b_tail_ty = tail_field_ty.instantiate(tcx, b_args);
-
-                    // Substitute just the unsizing params from B into A. The type after
-                    // this substitution must be equal to B. This is so we don't unsize
-                    // unrelated type parameters.
-                    let new_a_args =
-                        tcx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
-                            if unsizing_params.contains(i as u32) { b_args[i] } else { a }
-                        }));
-                    let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_args);
-
-                    // Finally, we require that `TailA: Unsize<TailB>` for the tail field
-                    // types.
-                    ecx.eq(param_env, unsized_a_ty, b_ty)?;
-                    ecx.add_goal(Goal::new(
-                        tcx,
-                        param_env,
-                        ty::TraitRef::new(
-                            tcx,
-                            tcx.lang_items().unsize_trait().unwrap(),
-                            [a_tail_ty, b_tail_ty],
-                        ),
-                    ));
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    result_to_single(
+                        ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
+                        BuiltinImplSource::Misc,
+                    )
                 }
-                // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
+
+                //  `(A, B, T)` -> `(A, B, U)` where `T: Unsize<U>`
                 (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
                     if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
                 {
-                    let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
-                    let b_last_ty = b_tys.last().unwrap();
-
-                    // Substitute just the tail field of B., and require that they're equal.
-                    let unsized_a_ty =
-                        Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied());
-                    ecx.eq(param_env, unsized_a_ty, b_ty)?;
-
-                    // Similar to ADTs, require that the rest of the fields are equal.
-                    ecx.add_goal(Goal::new(
-                        tcx,
-                        param_env,
-                        ty::TraitRef::new(
-                            tcx,
-                            tcx.lang_items().unsize_trait().unwrap(),
-                            [*a_last_ty, *b_last_ty],
-                        ),
-                    ));
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    result_to_single(
+                        ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys),
+                        BuiltinImplSource::TupleUnsizing,
+                    )
                 }
-                _ => Err(NoSolution),
+
+                _ => vec![],
             }
         })
     }
+}
 
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    /// Trait upcasting allows for coercions between trait objects:
+    /// ```ignore (builtin impl example)
+    /// trait Super {}
+    /// trait Trait: Super {}
+    /// // results in builtin impls upcasting to a super trait
+    /// impl<'a, 'b: 'a> Unsize<dyn Super + 'a> for dyn Trait + 'b {}
+    /// // and impls removing auto trait bounds.
+    /// impl<'a, 'b: 'a> Unsize<dyn Trait + 'a> for dyn Trait + Send + 'b {}
+    /// ```
     fn consider_builtin_dyn_upcast_candidates(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        a_ty: Ty<'tcx>,
-        b_ty: Ty<'tcx>,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        a_region: ty::Region<'tcx>,
+        b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        b_region: ty::Region<'tcx>,
     ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
-        if a_ty.is_ty_var() || b_ty.is_ty_var() {
-            bug!("unexpected type variable in unsize goal")
-        }
-
-        let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
-            return vec![];
-        };
-        let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
-            return vec![];
-        };
-
         let tcx = self.tcx();
+        let Goal { predicate: (a_ty, b_ty), .. } = goal;
+
         // All of a's auto traits need to be in b's auto traits.
         let auto_traits_compatible =
             b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
@@ -665,12 +560,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                         let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
 
                         // We also require that A's lifetime outlives B's lifetime.
-                        ecx.eq(param_env, new_a_ty, b_ty)?;
-                        ecx.add_goal(Goal::new(
-                            tcx,
-                            param_env,
-                            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
-                        ));
+                        ecx.eq(goal.param_env, new_a_ty, b_ty)?;
+                        ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_region, b_region)));
                         ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                     },
                 )
@@ -703,6 +594,161 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         responses
     }
 
+    /// ```ignore (builtin impl example)
+    /// trait Trait {
+    ///     fn foo(&self);
+    /// }
+    /// // results in the following builtin impl
+    /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
+    /// ```
+    fn consider_builtin_unsize_to_dyn(
+        &mut self,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        b_region: ty::Region<'tcx>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+        let Goal { predicate: (a_ty, _b_ty), .. } = goal;
+
+        // Can only unsize to an object-safe trait
+        if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) {
+            return Err(NoSolution);
+        }
+
+        // Check that the type implements all of the predicates of the trait object.
+        // (i.e. the principal, all of the associated types match, and any auto traits)
+        self.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))));
+
+        // The type must be `Sized` to be unsized.
+        if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
+            self.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
+        } else {
+            return Err(NoSolution);
+        }
+
+        // The type must outlive the lifetime of the `dyn` we're unsizing into.
+        self.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
+    /// We have the following builtin impls for arrays:
+    /// ```ignore (builtin impl example)
+    /// impl<T: ?Sized, const N: usize> Unsize<[T]> for [T; N] {}
+    /// ```
+    /// While the impl itself could theoretically not be builtin,
+    /// the actual unsizing behavior is builtin. Its also easier to
+    /// make all impls of `Unsize` builtin as we're able to use
+    /// `#[rustc_deny_explicit_impl]` in this case.
+    fn consider_builtin_array_unsize(
+        &mut self,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        a_elem_ty: Ty<'tcx>,
+        b_elem_ty: Ty<'tcx>,
+    ) -> QueryResult<'tcx> {
+        self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
+    /// We generate a builtin `Unsize` impls for structs with generic parameters only
+    /// mentioned by the last field.
+    /// ```ignore (builtin impl example)
+    /// struct Foo<T, U: ?Sized> {
+    ///     sized_field: Vec<T>,
+    ///     unsizable: Box<U>,
+    /// }
+    /// // results in the following builtin impl
+    /// impl<T: ?Sized, U: ?Sized, V: ?Sized> Unsize<Foo<T, V>> for Foo<T, U>
+    /// where
+    ///     Box<U>: Unsize<Box<V>>,
+    /// {}
+    /// ```
+    fn consider_builtin_struct_unsize(
+        &mut self,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        def: ty::AdtDef<'tcx>,
+        a_args: ty::GenericArgsRef<'tcx>,
+        b_args: ty::GenericArgsRef<'tcx>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+        let Goal { predicate: (_a_ty, b_ty), .. } = goal;
+
+        let unsizing_params = tcx.unsizing_params_for_adt(def.did());
+        // We must be unsizing some type parameters. This also implies
+        // that the struct has a tail field.
+        if unsizing_params.is_empty() {
+            return Err(NoSolution);
+        }
+
+        let tail_field = def.non_enum_variant().tail();
+        let tail_field_ty = tcx.type_of(tail_field.did);
+
+        let a_tail_ty = tail_field_ty.instantiate(tcx, a_args);
+        let b_tail_ty = tail_field_ty.instantiate(tcx, b_args);
+
+        // Substitute just the unsizing params from B into A. The type after
+        // this substitution must be equal to B. This is so we don't unsize
+        // unrelated type parameters.
+        let new_a_args = tcx.mk_args_from_iter(
+            a_args
+                .iter()
+                .enumerate()
+                .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }),
+        );
+        let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args);
+
+        // Finally, we require that `TailA: Unsize<TailB>` for the tail field
+        // types.
+        self.eq(goal.param_env, unsized_a_ty, b_ty)?;
+        self.add_goal(goal.with(
+            tcx,
+            ty::TraitRef::new(
+                tcx,
+                tcx.lang_items().unsize_trait().unwrap(),
+                [a_tail_ty, b_tail_ty],
+            ),
+        ));
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
+    /// We generate the following builtin impl for tuples of all sizes.
+    ///
+    /// This impl is still unstable and we emit a feature error when it
+    /// when it is used by a coercion.
+    /// ```ignore (builtin impl example)
+    /// impl<T: ?Sized, U: ?Sized, V: ?Sized> Unsize<(T, V)> for (T, U)
+    /// where
+    ///     U: Unsize<V>,
+    /// {}
+    /// ```
+    fn consider_builtin_tuple_unsize(
+        &mut self,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        a_tys: &'tcx ty::List<Ty<'tcx>>,
+        b_tys: &'tcx ty::List<Ty<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+        let Goal { predicate: (_a_ty, b_ty), .. } = goal;
+
+        let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
+        let &b_last_ty = b_tys.last().unwrap();
+
+        // Substitute just the tail field of B., and require that they're equal.
+        let unsized_a_ty =
+            Ty::new_tup_from_iter(tcx, a_rest_tys.iter().copied().chain([b_last_ty]));
+        self.eq(goal.param_env, unsized_a_ty, b_ty)?;
+
+        // Similar to ADTs, require that we can unsize the tail.
+        self.add_goal(goal.with(
+            tcx,
+            ty::TraitRef::new(
+                tcx,
+                tcx.lang_items().unsize_trait().unwrap(),
+                [a_last_ty, b_last_ty],
+            ),
+        ));
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
     // Return `Some` if there is an impl (built-in or user provided) that may
     // hold for the self type of the goal, which for coherence and soundness
     // purposes must disqualify the built-in auto impl assembled by considering
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c26849d484e..94d3cd035aa 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -161,7 +161,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         let (full_env, full_user_env) = self
             .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds)
             .unwrap_or_else(|| {
-                panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
+                panic!("Failed to fully process: {ty:?} {trait_did:?} {orig_env:?}")
             });
 
         debug!(
@@ -178,7 +178,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
         let errors = ocx.select_all_or_error();
         if !errors.is_empty() {
-            panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+            panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}");
         }
 
         let outlives_env = OutlivesEnvironment::new(full_env);
@@ -339,7 +339,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         return None;
                     }
                 }
-                _ => panic!("Unexpected error for '{:?}': {:?}", ty, result),
+                _ => panic!("Unexpected error for '{ty:?}': {result:?}"),
             };
 
             let normalized_preds =
@@ -747,7 +747,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // subobligations or getting an error) when we started off with
                             // inference variables
                             if p.term().skip_binder().has_infer_types() {
-                                panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
+                                panic!("Unexpected result when selecting {ty:?} {obligation:?}")
                             }
                         }
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 039e4ec9afd..19d5baa30ec 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -357,7 +357,7 @@ fn impl_intersection_has_negative_obligation(
         Err(err) => {
             tcx.sess.delay_span_bug(
                 tcx.def_span(impl1_def_id),
-                format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
+                format!("failed to fully normalize {impl1_def_id:?}: {err:?}"),
             );
             return false;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index cbd81cae989..14020c05251 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -226,7 +226,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                 let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
                 (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
             }
-            _ => panic!("non-FnLike node found: {:?}", node),
+            _ => panic!("non-FnLike node found: {node:?}"),
         })
     }
 
@@ -273,10 +273,10 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             found_str,
         );
 
-        err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
+        err.span_label(span, format!("expected {kind} that takes {expected_str}"));
 
         if let Some(found_span) = found_span {
-            err.span_label(found_span, format!("takes {}", found_str));
+            err.span_label(found_span, format!("takes {found_str}"));
 
             // Suggest to take and ignore the arguments with expected_args_length `_`s if
             // found arguments is empty (assume the user just wants to ignore args in this case).
@@ -289,7 +289,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                         "consider changing the closure to take and ignore the expected argument{}",
                         pluralize!(expected_args.len())
                     ),
-                    format!("|{}|", underscores),
+                    format!("|{underscores}|"),
                     Applicability::MachineApplicable,
                 );
             }
@@ -304,7 +304,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                     err.span_suggestion_verbose(
                         found_span,
                         "change the closure to take multiple arguments instead of a single tuple",
-                        format!("|{}|", sugg),
+                        format!("|{sugg}|"),
                         Applicability::MachineApplicable,
                     );
                 }
@@ -703,9 +703,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             .get_parent_trait_ref(obligation.cause.code())
                             .map(|(t, s)| {
                                 (
-                                    format!(" in `{}`", t),
-                                    format!("within `{}`, ", t),
-                                    s.map(|s| (format!("within this `{}`", t), s)),
+                                    format!(" in `{t}`"),
+                                    format!("within `{t}`, "),
+                                    s.map(|s| (format!("within this `{t}`"), s)),
                                 )
                             })
                             .unwrap_or_default();
@@ -1070,7 +1070,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 // which bounds actually failed to hold.
                                 self.tcx.sess.struct_span_err(
                                     span,
-                                    format!("the type `{}` is not well-formed", ty),
+                                    format!("the type `{ty}` is not well-formed"),
                                 )
                             }
                         }
@@ -1108,7 +1108,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                         let mut diag = self.tcx.sess.struct_span_err(
                             span,
-                            format!("the constant `{}` is not of type `{}`", ct, ty),
+                            format!("the constant `{ct}` is not of type `{ty}`"),
                         );
                         self.note_type_err(
                             &mut diag,
@@ -1980,7 +1980,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     if all_traits_equal {
                         format!("\n  {}", c.self_ty())
                     } else {
-                        format!("\n  {}", c)
+                        format!("\n  {c}")
                     }
                 })
                 .collect();
@@ -2178,10 +2178,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
             );
             let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
-            let crate_msg = format!(
-                "perhaps two different versions of crate `{}` are being used?",
-                trait_crate
-            );
+            let crate_msg =
+                format!("perhaps two different versions of crate `{trait_crate}` are being used?");
             err.note(crate_msg);
             suggested = true;
         }
@@ -2309,7 +2307,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         err.cancel();
                         return;
                     }
-                    err.note(format!("cannot satisfy `{}`", predicate));
+                    err.note(format!("cannot satisfy `{predicate}`"));
                     let impl_candidates = self
                         .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
                     if impl_candidates.len() < 10 {
@@ -2373,7 +2371,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         if let Some(local_def_id) = data.trait_ref.def_id.as_local()
                             && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id)
                             && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) {
-                            err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name));
+                            err.span_label(method_ref.span, format!("`{trait_name}::{assoc_item_name}` defined here"));
                         }
 
                         err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
@@ -2474,7 +2472,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         ErrorCode::E0284,
                         true,
                     );
-                    err.note(format!("cannot satisfy `{}`", predicate));
+                    err.note(format!("cannot satisfy `{predicate}`"));
                     err
                 } else {
                     // If we can't find a substitution, just print a generic error
@@ -2485,7 +2483,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "type annotations needed: cannot satisfy `{}`",
                         predicate,
                     );
-                    err.span_label(span, format!("cannot satisfy `{}`", predicate));
+                    err.span_label(span, format!("cannot satisfy `{predicate}`"));
                     err
                 }
             }
@@ -2513,7 +2511,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "type annotations needed: cannot satisfy `{}`",
                         predicate,
                     );
-                    err.span_label(span, format!("cannot satisfy `{}`", predicate));
+                    err.span_label(span, format!("cannot satisfy `{predicate}`"));
                     err
                 }
             }
@@ -2528,7 +2526,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     "type annotations needed: cannot satisfy `{}`",
                     predicate,
                 );
-                err.span_label(span, format!("cannot satisfy `{}`", predicate));
+                err.span_label(span, format!("cannot satisfy `{predicate}`"));
                 err
             }
         };
@@ -2565,7 +2563,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
         }
-        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
         crate_names.sort();
         crate_names.dedup();
         post.sort();
@@ -2592,7 +2590,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             predicate
         );
         let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
-            format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
+            format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
         } else if post.len() == 1 {
             format!(": `{}`", post[0])
         } else {
@@ -2601,7 +2599,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
         match (spans.len(), crates.len(), crate_names.len()) {
             (0, 0, 0) => {
-                err.note(format!("cannot satisfy `{}`", predicate));
+                err.note(format!("cannot satisfy `{predicate}`"));
             }
             (0, _, 1) => {
                 err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
@@ -2772,7 +2770,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err.span_suggestion_verbose(
             span,
             "consider relaxing the implicit `Sized` restriction",
-            format!("{} ?Sized", separator),
+            format!("{separator} ?Sized"),
             Applicability::MachineApplicable,
         );
     }
@@ -2863,7 +2861,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             })
             .unwrap_or_else(|| {
-                format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message)
+                format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
             })
     }
 
@@ -3151,11 +3149,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
         err.span_label(
             closure_span,
-            format!("this closure implements `{}`, not `{}`", found_kind, kind),
+            format!("this closure implements `{found_kind}`, not `{kind}`"),
         );
         err.span_label(
             obligation.cause.span,
-            format!("the requirement to implement `{}` derives from here", kind),
+            format!("the requirement to implement `{kind}` derives from here"),
         );
 
         // Additional context information explaining why the closure only implements
@@ -3382,8 +3380,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 let const_span = self.tcx.def_span(uv.def);
                 match self.tcx.sess.source_map().span_to_snippet(const_span) {
                     Ok(snippet) => err.help(format!(
-                        "try adding a `where` bound using this expression: `where [(); {}]:`",
-                        snippet
+                        "try adding a `where` bound using this expression: `where [(); {snippet}]:`"
                     )),
                     _ => err.help("consider adding a `where` bound using this expression"),
                 };
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index a530b27bc91..0e73bad1918 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -170,7 +170,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
         if let Some(k) = obligation.cause.span.desugaring_kind() {
             flags.push((sym::from_desugaring, None));
-            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
+            flags.push((sym::from_desugaring, Some(format!("{k:?}"))));
         }
 
         if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
@@ -258,9 +258,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_string())));
                 let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
-                flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
+                flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
                 if let Some(n) = len {
-                    flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
+                    flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
                 }
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the array's type's original
@@ -579,7 +579,7 @@ impl<'tcx> OnUnimplementedFormatString {
                                     "there is no parameter `{}` on {}",
                                     s,
                                     if trait_def_id == item_def_id {
-                                        format!("trait `{}`", trait_name)
+                                        format!("trait `{trait_name}`")
                                     } else {
                                         "impl".to_string()
                                     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 1eb4447ae4e..31f70bbd34d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -479,13 +479,13 @@ fn suggest_restriction<'tcx>(
                 .visit_ty(input);
         }
         // The type param `T: Trait` we will suggest to introduce.
-        let type_param = format!("{}: {}", type_param_name, bound_str);
+        let type_param = format!("{type_param_name}: {bound_str}");
 
         let mut sugg = vec![
             if let Some(span) = hir_generics.span_for_param_suggestion() {
-                (span, format!(", {}", type_param))
+                (span, format!(", {type_param}"))
             } else {
-                (hir_generics.span, format!("<{}>", type_param))
+                (hir_generics.span, format!("<{type_param}>"))
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
@@ -530,7 +530,7 @@ fn suggest_restriction<'tcx>(
 
         err.span_suggestion_verbose(
             sp,
-            format!("consider further restricting {}", msg),
+            format!("consider further restricting {msg}"),
             suggestion,
             Applicability::MachineApplicable,
         );
@@ -694,7 +694,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 term
                             );
                         } else {
-                            constraint.push_str(&format!("<{} = {}>", name, term));
+                            constraint.push_str(&format!("<{name} = {term}>"));
                         }
                     }
 
@@ -1016,7 +1016,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     let name = self.tcx.def_path_str(def_id);
                     err.span_label(
                         self.tcx.def_span(def_id),
-                        format!("consider calling the constructor for `{}`", name),
+                        format!("consider calling the constructor for `{name}`"),
                     );
                     name
                 }
@@ -1395,7 +1395,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     // Because of this, we modify the error to refer to the original obligation and
                     // return early in the caller.
 
-                    let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+                    let msg = format!("the trait bound `{old_pred}` is not satisfied");
                     if has_custom_message {
                         err.note(msg);
                     } else {
@@ -1435,7 +1435,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 err.multipart_suggestion_verbose(
                                     sugg_msg,
                                     vec![
-                                        (span.shrink_to_lo(), format!("({}", sugg_prefix)),
+                                        (span.shrink_to_lo(), format!("({sugg_prefix}")),
                                         (span.shrink_to_hi(), ")".to_string()),
                                     ],
                                     Applicability::MaybeIncorrect,
@@ -1471,7 +1471,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             vec![(span.shrink_to_lo(), sugg_prefix)]
                         } else {
                             vec![
-                                (span.shrink_to_lo(), format!("{}(", sugg_prefix)),
+                                (span.shrink_to_lo(), format!("{sugg_prefix}(")),
                                 (span.shrink_to_hi(), ")".to_string()),
                             ]
                         };
@@ -1702,8 +1702,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             hir.get_if_local(*def_id)
                     {
                         let msg = format!(
-                            "alternatively, consider making `fn {}` asynchronous",
-                            ident
+                            "alternatively, consider making `fn {ident}` asynchronous"
                         );
                         if vis_span.is_empty() {
                             err.span_suggestion_verbose(
@@ -1954,10 +1953,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         // don't print out the [type error] here
                         err.delay_as_bug();
                     } else {
-                        err.span_label(
-                            expr.span,
-                            format!("this returned value is of type `{}`", ty),
-                        );
+                        err.span_label(expr.span, format!("this returned value is of type `{ty}`"));
                     }
                 }
             }
@@ -2458,8 +2454,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
             err.clear_code();
             err.set_primary_message(format!(
-                "{} cannot be {} between threads safely",
-                future_or_generator, trait_verb
+                "{future_or_generator} cannot be {trait_verb} between threads safely"
             ));
 
             let original_span = err.span.primary_span().unwrap();
@@ -2468,7 +2463,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let message = outer_generator
                 .and_then(|generator_did| {
                     Some(match self.tcx.generator_kind(generator_did).unwrap() {
-                        GeneratorKind::Gen => format!("generator is not {}", trait_name),
+                        GeneratorKind::Gen => format!("generator is not {trait_name}"),
                         GeneratorKind::Async(AsyncGeneratorKind::Fn) => self
                             .tcx
                             .parent(generator_did)
@@ -2476,73 +2471,73 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
                             .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
                             .map(|name| {
-                                format!("future returned by `{}` is not {}", name, trait_name)
+                                format!("future returned by `{name}` is not {trait_name}")
                             })?,
                         GeneratorKind::Async(AsyncGeneratorKind::Block) => {
-                            format!("future created by async block is not {}", trait_name)
+                            format!("future created by async block is not {trait_name}")
                         }
                         GeneratorKind::Async(AsyncGeneratorKind::Closure) => {
-                            format!("future created by async closure is not {}", trait_name)
+                            format!("future created by async closure is not {trait_name}")
                         }
                     })
                 })
-                .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name));
+                .unwrap_or_else(|| format!("{future_or_generator} is not {trait_name}"));
 
             span.push_span_label(original_span, message);
             err.set_span(span);
 
-            format!("is not {}", trait_name)
+            format!("is not {trait_name}")
         } else {
             format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
         };
 
-        let mut explain_yield =
-            |interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
-                let mut span = MultiSpan::from_span(yield_span);
-                let snippet = match source_map.span_to_snippet(interior_span) {
-                    // #70935: If snippet contains newlines, display "the value" instead
-                    // so that we do not emit complex diagnostics.
-                    Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet),
-                    _ => "the value".to_string(),
-                };
-                // note: future is not `Send` as this value is used across an await
-                //   --> $DIR/issue-70935-complex-spans.rs:13:9
-                //    |
-                // LL |            baz(|| async {
-                //    |  ______________-
-                //    | |
-                //    | |
-                // LL | |              foo(tx.clone());
-                // LL | |          }).await;
-                //    | |          - ^^^^^^ await occurs here, with value maybe used later
-                //    | |__________|
-                //    |            has type `closure` which is not `Send`
-                // note: value is later dropped here
-                // LL | |          }).await;
-                //    | |                  ^
-                //
-                span.push_span_label(
-                    yield_span,
-                    format!("{} occurs here, with {} maybe used later", await_or_yield, snippet),
-                );
-                span.push_span_label(
-                    interior_span,
-                    format!("has type `{}` which {}", target_ty, trait_explanation),
-                );
-                if let Some(scope_span) = scope_span {
-                    let scope_span = source_map.end_point(scope_span);
+        let mut explain_yield = |interior_span: Span,
+                                 yield_span: Span,
+                                 scope_span: Option<Span>| {
+            let mut span = MultiSpan::from_span(yield_span);
+            let snippet = match source_map.span_to_snippet(interior_span) {
+                // #70935: If snippet contains newlines, display "the value" instead
+                // so that we do not emit complex diagnostics.
+                Ok(snippet) if !snippet.contains('\n') => format!("`{snippet}`"),
+                _ => "the value".to_string(),
+            };
+            // note: future is not `Send` as this value is used across an await
+            //   --> $DIR/issue-70935-complex-spans.rs:13:9
+            //    |
+            // LL |            baz(|| async {
+            //    |  ______________-
+            //    | |
+            //    | |
+            // LL | |              foo(tx.clone());
+            // LL | |          }).await;
+            //    | |          - ^^^^^^ await occurs here, with value maybe used later
+            //    | |__________|
+            //    |            has type `closure` which is not `Send`
+            // note: value is later dropped here
+            // LL | |          }).await;
+            //    | |                  ^
+            //
+            span.push_span_label(
+                yield_span,
+                format!("{await_or_yield} occurs here, with {snippet} maybe used later"),
+            );
+            span.push_span_label(
+                interior_span,
+                format!("has type `{target_ty}` which {trait_explanation}"),
+            );
+            if let Some(scope_span) = scope_span {
+                let scope_span = source_map.end_point(scope_span);
 
-                    let msg = format!("{} is later dropped here", snippet);
-                    span.push_span_label(scope_span, msg);
-                }
-                err.span_note(
+                let msg = format!("{snippet} is later dropped here");
+                span.push_span_label(scope_span, msg);
+            }
+            err.span_note(
                     span,
                     format!(
-                        "{} {} as this value is used across {}",
-                        future_or_generator, trait_explanation, an_await_or_yield
+                        "{future_or_generator} {trait_explanation} as this value is used across {an_await_or_yield}"
                     ),
                 );
-            };
+        };
         match interior_or_upvar_span {
             GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
                 if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
@@ -2552,15 +2547,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         span.push_span_label(
                             await_span,
                             format!(
-                                "await occurs here on type `{}`, which {}",
-                                target_ty, trait_explanation
+                                "await occurs here on type `{target_ty}`, which {trait_explanation}"
                             ),
                         );
                         err.span_note(
                             span,
                             format!(
-                                "future {not_trait} as it awaits another future which {not_trait}",
-                                not_trait = trait_explanation
+                                "future {trait_explanation} as it awaits another future which {trait_explanation}"
                             ),
                         );
                     } else {
@@ -2643,18 +2636,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         let ref_kind = if is_mut { "&mut" } else { "&" };
                         (
                             format!(
-                                "has type `{}` which {}, because `{}` is not `{}`",
-                                target_ty, trait_explanation, ref_ty, ref_ty_trait
+                                "has type `{target_ty}` which {trait_explanation}, because `{ref_ty}` is not `{ref_ty_trait}`"
                             ),
                             format!(
-                                "captured value {} because `{}` references cannot be sent unless their referent is `{}`",
-                                trait_explanation, ref_kind, ref_ty_trait
+                                "captured value {trait_explanation} because `{ref_kind}` references cannot be sent unless their referent is `{ref_ty_trait}`"
                             ),
                         )
                     }
                     None => (
-                        format!("has type `{}` which {}", target_ty, trait_explanation),
-                        format!("captured value {}", trait_explanation),
+                        format!("has type `{target_ty}` which {trait_explanation}"),
+                        format!("captured value {trait_explanation}"),
                     ),
                 };
 
@@ -2743,8 +2734,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
                 err.note(format!(
-                    "required so that the lifetime bound of `{}` for `{}` is satisfied",
-                    region, object_ty,
+                    "required so that the lifetime bound of `{region}` for `{object_ty}` is satisfied",
                 ));
             }
             ObligationCauseCode::ItemObligation(_)
@@ -3064,7 +3054,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 let mut msg =
                                     "required because it captures the following types: ".to_owned();
                                 for ty in bound_tys.skip_binder() {
-                                    with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
+                                    with_forced_trimmed_paths!(write!(msg, "`{ty}`, ").unwrap());
                                 }
                                 err.note(msg.trim_end_matches(", ").to_string())
                             }
@@ -3078,7 +3068,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                     "required because it captures the following types: ".to_owned();
                                 for bty in tcx.generator_hidden_types(*def_id) {
                                     let ty = bty.instantiate(tcx, args);
-                                    write!(msg, "`{}`, ", ty).unwrap();
+                                    write!(msg, "`{ty}`, ").unwrap();
                                 }
                                 err.note(msg.trim_end_matches(", ").to_string())
                             }
@@ -3513,7 +3503,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     trait_pred.skip_binder().self_ty(),
                     diagnostic_name,
                 ),
-                format!("#[derive({})]\n", diagnostic_name),
+                format!("#[derive({diagnostic_name})]\n"),
                 Applicability::MaybeIncorrect,
             );
         }
@@ -3999,7 +3989,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             .map(|trait_ref| trait_ref.trait_ref.self_ty())
             .find(|t| is_slice(*t))
         {
-            let msg = format!("convert the array to a `{}` slice instead", slice_ty);
+            let msg = format!("convert the array to a `{slice_ty}` slice instead");
 
             if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                 let mut suggestions = vec![];
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index abb05be80e9..76752edc4ae 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -517,8 +517,7 @@ fn virtual_call_violation_for_method<'tcx>(
                     tcx.sess.delay_span_bug(
                         tcx.def_span(method.def_id),
                         format!(
-                            "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
-                            abi
+                            "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
                         ),
                     );
                 }
@@ -536,8 +535,7 @@ fn virtual_call_violation_for_method<'tcx>(
                     tcx.sess.delay_span_bug(
                         tcx.def_span(method.def_id),
                         format!(
-                            "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}",
-                            trait_object_ty, abi
+                            "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
                         ),
                     );
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a35dd1f1a59..98f45826727 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -483,8 +483,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
 
         assert!(
             !value.has_escaping_bound_vars(),
-            "Normalizing {:?} without wrapping in a `Binder`",
-            value
+            "Normalizing {value:?} without wrapping in a `Binder`"
         );
 
         if !needs_normalization(&value, self.param_env.reveal()) {
@@ -1932,7 +1931,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
-                    format!("Cannot project an associated type from `{:?}`", impl_source),
+                    format!("Cannot project an associated type from `{impl_source:?}`"),
                 );
                 return Err(());
             }
@@ -2303,8 +2302,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         }
         Err(e) => {
             let msg = format!(
-                "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
-                obligation, poly_cache_entry, e,
+                "Failed to unify obligation `{obligation:?}` with poly_projection `{poly_cache_entry:?}`: {e:?}",
             );
             debug!("confirm_param_env_candidate: {}", msg);
             let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg);
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index d45cf94f731..87beaddc6c2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -299,7 +299,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     if !tcx.sess.opts.actually_rustdoc {
                         tcx.sess.delay_span_bug(
                             DUMMY_SP,
-                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+                            format!("unexpected ambiguity: {c_data:?} {result:?}"),
                         );
                     }
                     return Err(NoSolution);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 5420caee329..c99e018e9ae 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -77,8 +77,7 @@ where
     let pre_obligations = infcx.take_registered_region_obligations();
     assert!(
         pre_obligations.is_empty(),
-        "scrape_region_constraints: incoming region obligations = {:#?}",
-        pre_obligations,
+        "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}",
     );
 
     let value = infcx.commit_if_ok(|_| {
@@ -92,7 +91,7 @@ where
         } else {
             Err(infcx.tcx.sess.delay_span_bug(
                 DUMMY_SP,
-                format!("errors selecting obligation during MIR typeck: {:?}", errors),
+                format!("errors selecting obligation during MIR typeck: {errors:?}"),
             ))
         }
     })?;
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index b4875ec0ea3..c29696bc817 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -74,22 +74,21 @@ impl IntercrateAmbiguityCause {
         match self {
             IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => {
                 let self_desc = if let Some(ty) = self_desc {
-                    format!(" for type `{}`", ty)
+                    format!(" for type `{ty}`")
                 } else {
                     String::new()
                 };
-                format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
+                format!("downstream crates may implement trait `{trait_desc}`{self_desc}")
             }
             IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => {
                 let self_desc = if let Some(ty) = self_desc {
-                    format!(" for type `{}`", ty)
+                    format!(" for type `{ty}`")
                 } else {
                     String::new()
                 };
                 format!(
-                    "upstream crates may add a new impl of trait `{}`{} \
-                     in future versions",
-                    trait_desc, self_desc
+                    "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \
+                     in future versions"
                 )
             }
             IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(),
@@ -2410,8 +2409,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 let guar = self.infcx.tcx.sess.delay_span_bug(
                     obligation.cause.span,
                     format!(
-                        "Impl {:?} was matchable against {:?} but now is not",
-                        impl_def_id, obligation
+                        "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
                     ),
                 );
                 let value = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index b61b209654c..61e631c438d 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -388,16 +388,16 @@ fn report_conflicting_impls<'tcx>(
                     impl_span,
                     format!(
                         "conflicting implementation{}",
-                        overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{}`", ty))
+                        overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{ty}`"))
                     ),
                 );
             }
             Err(cname) => {
                 let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
                     Some(s) => {
-                        format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
+                        format!("conflicting implementation in crate `{cname}`:\n- {s}")
                     }
-                    None => format!("conflicting implementation in crate `{}`", cname),
+                    None => format!("conflicting implementation in crate `{cname}`"),
                 };
                 err.note(msg);
             }
@@ -514,8 +514,7 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
         pretty_predicates.push(p.to_string());
     }
 
-    pretty_predicates
-        .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty)));
+    pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
 
     if !pretty_predicates.is_empty() {
         write!(w, "\n  where {}", pretty_predicates.join(", ")).unwrap();
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 3eab885a089..4c27fe8b29b 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -50,7 +50,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
         diag.span_label(self.top().1, top_label);
         if self.path.len() > 1 {
             for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
-                diag.span_label(*sp, format!("referenced here ({})", use_desc));
+                diag.span_label(*sp, format!("referenced here ({use_desc})"));
             }
         }
         if self.top().1 != self.bottom().1 {
@@ -58,7 +58,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
             // redundant labels.
             diag.span_label(
                 self.bottom().1,
-                format!("trait alias used in trait object type ({})", use_desc),
+                format!("trait alias used in trait object type ({use_desc})"),
             );
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index c4cc89aa907..3964dda1fdb 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -195,11 +195,7 @@ fn dump_vtable_entries<'tcx>(
     trait_ref: ty::PolyTraitRef<'tcx>,
     entries: &[VtblEntry<'tcx>],
 ) {
-    tcx.sess.emit_err(DumpVTableEntries {
-        span: sp,
-        trait_ref,
-        entries: format!("{:#?}", entries),
-    });
+    tcx.sess.emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") });
 }
 
 fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index fa1976510cf..7eb1042d2f8 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,13 +1,22 @@
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 use std::iter;
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { assumed_wf_types, ..*providers };
+    *providers = Providers {
+        assumed_wf_types,
+        assumed_wf_types_for_rpitit: |tcx, def_id| {
+            assert!(tcx.is_impl_trait_in_trait(def_id.to_def_id()));
+            tcx.assumed_wf_types(def_id)
+        },
+        ..*providers
+    };
 }
 
 fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
@@ -42,6 +51,81 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
             let mut impl_spans = impl_spans(tcx, def_id);
             tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
         }
+        DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => match data {
+            ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => {
+                let hir::OpaqueTy { lifetime_mapping, .. } =
+                    *tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty();
+                // We need to remap all of the late-bound lifetimes in theassumed wf types
+                // of the fn (which are represented as ReFree) to the early-bound lifetimes
+                // of the RPITIT (which are represented by ReEarlyBound owned by the opaque).
+                // Luckily, this is very easy to do because we already have that mapping
+                // stored in the HIR of this RPITIT.
+                //
+                // Side-note: We don't really need to do this remapping for early-bound
+                // lifetimes because they're already "linked" by the bidirectional outlives
+                // predicates we insert in the `explicit_predicates_of` query for RPITITs.
+                let mut mapping = FxHashMap::default();
+                let generics = tcx.generics_of(def_id);
+                for &(lifetime, new_early_bound_def_id) in
+                    lifetime_mapping.expect("expected lifetime mapping for RPITIT")
+                {
+                    if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) =
+                        tcx.named_bound_var(lifetime.hir_id)
+                    {
+                        let name = tcx.hir().name(lifetime.hir_id);
+                        let index = generics
+                            .param_def_id_to_index(tcx, new_early_bound_def_id.to_def_id())
+                            .unwrap();
+                        mapping.insert(
+                            ty::Region::new_free(
+                                tcx,
+                                fn_def_id,
+                                ty::BoundRegionKind::BrNamed(def_id, name),
+                            ),
+                            ty::Region::new_early_bound(
+                                tcx,
+                                ty::EarlyBoundRegion {
+                                    def_id: new_early_bound_def_id.to_def_id(),
+                                    index,
+                                    name,
+                                },
+                            ),
+                        );
+                    }
+                }
+                // FIXME: This could use a real folder, I guess.
+                let remapped_wf_tys = tcx.fold_regions(
+                    tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(),
+                    |region, _| {
+                        // If `region` is a `ReFree` that is captured by the
+                        // opaque, remap it to its corresponding the early-
+                        // bound region.
+                        if let Some(remapped_region) = mapping.get(&region) {
+                            *remapped_region
+                        } else {
+                            region
+                        }
+                    },
+                );
+                tcx.arena.alloc_from_iter(remapped_wf_tys)
+            }
+            // Assumed wf types for RPITITs in an impl just inherit (and instantiate)
+            // the assumed wf types of the trait's RPITIT GAT.
+            ty::ImplTraitInTraitData::Impl { .. } => {
+                let impl_def_id = tcx.local_parent(def_id);
+                let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap();
+                let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
+                    tcx,
+                    impl_def_id.to_def_id(),
+                    tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args,
+                );
+                tcx.arena.alloc_from_iter(
+                    ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id))
+                        .iter_instantiated_copied(tcx, args)
+                        .chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()),
+                )
+            }
+        },
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
         DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
             DefKind::TyAlias => ty::List::empty(),
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 55b8857ed39..147b600f7ba 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(assert_matches)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
+#![feature(if_let_guard)]
 #![feature(never_type)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 2055852eda0..791a1f4fa99 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -129,7 +129,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // sure that this will succeed without errors anyway.
 
     if tcx.def_kind(def_id) == DefKind::AssocFn
-        && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer
+        && let assoc_item = tcx.associated_item(def_id)
+        && assoc_item.container == ty::AssocItemContainer::TraitContainer
+        && assoc_item.defaultness(tcx).has_value()
     {
         let sig = tcx.fn_sig(def_id).instantiate_identity();
         // We accounted for the binder of the fn sig, so skip the binder.
@@ -179,8 +181,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
         if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind()
-            && self.tcx.is_impl_trait_in_trait(unshifted_alias_ty.def_id)
-            && self.tcx.impl_trait_in_trait_parent_fn(unshifted_alias_ty.def_id) == self.fn_def_id
+            && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }
+                    | ty::ImplTraitInTraitData::Impl { fn_def_id, .. })
+                = self.tcx.opt_rpitit_info(unshifted_alias_ty.def_id)
+            && fn_def_id == self.fn_def_id
             && self.seen.insert(unshifted_alias_ty.def_id)
         {
             // We have entered some binders as we've walked into the
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index a7cd7aa2c4f..c2655d68b79 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -408,7 +408,7 @@ pub fn debug_bound_var<T: std::fmt::Write>(
     var: impl std::fmt::Debug,
 ) -> Result<(), std::fmt::Error> {
     if debruijn == INNERMOST {
-        write!(fmt, "^{:?}", var)
+        write!(fmt, "^{var:?}")
     } else {
         write!(fmt, "^{}_{:?}", debruijn.index(), var)
     }
diff --git a/config.example.toml b/config.example.toml
index 367f95b156f..b10922f8d04 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -690,10 +690,6 @@ changelog-seen = 2
 # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std`
 #validate-mir-opts = 3
 
-# Copy the linker, DLLs, and various libraries from MinGW into the rustc toolchain.
-# Only applies when the host or target is pc-windows-gnu.
-#include-mingw-linker = true
-
 # =============================================================================
 # Options for specific targets
 #
@@ -844,3 +840,7 @@ changelog-seen = 2
 #
 # Available options: fast, balanced, best
 #compression-profile = "fast"
+
+# Copy the linker, DLLs, and various libraries from MinGW into the rustc toolchain.
+# Only applies when the host or target is pc-windows-gnu.
+#include-mingw-linker = true
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 29e9423bb43..5481b327d69 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -2543,6 +2543,8 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(2, "b");
     /// a.insert(3, "c");
     /// a.insert(4, "c");
+    /// let cursor = a.lower_bound(Bound::Included(&2));
+    /// assert_eq!(cursor.key(), Some(&2));
     /// let cursor = a.lower_bound(Bound::Excluded(&2));
     /// assert_eq!(cursor.key(), Some(&3));
     /// ```
@@ -2582,6 +2584,8 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(2, "b");
     /// a.insert(3, "c");
     /// a.insert(4, "c");
+    /// let cursor = a.lower_bound_mut(Bound::Included(&2));
+    /// assert_eq!(cursor.key(), Some(&2));
     /// let cursor = a.lower_bound_mut(Bound::Excluded(&2));
     /// assert_eq!(cursor.key(), Some(&3));
     /// ```
@@ -2634,6 +2638,8 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(2, "b");
     /// a.insert(3, "c");
     /// a.insert(4, "c");
+    /// let cursor = a.upper_bound(Bound::Included(&3));
+    /// assert_eq!(cursor.key(), Some(&3));
     /// let cursor = a.upper_bound(Bound::Excluded(&3));
     /// assert_eq!(cursor.key(), Some(&2));
     /// ```
@@ -2673,6 +2679,8 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(2, "b");
     /// a.insert(3, "c");
     /// a.insert(4, "c");
+    /// let cursor = a.upper_bound_mut(Bound::Included(&3));
+    /// assert_eq!(cursor.key(), Some(&3));
     /// let cursor = a.upper_bound_mut(Bound::Excluded(&3));
     /// assert_eq!(cursor.key(), Some(&2));
     /// ```
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index c4461040b20..9da230915b8 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -1121,19 +1121,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// ```
     /// use std::collections::BTreeSet;
     ///
-    /// let set = BTreeSet::from([1, 2, 3]);
-    /// let mut set_iter = set.iter();
-    /// assert_eq!(set_iter.next(), Some(&1));
-    /// assert_eq!(set_iter.next(), Some(&2));
-    /// assert_eq!(set_iter.next(), Some(&3));
-    /// assert_eq!(set_iter.next(), None);
-    /// ```
-    ///
-    /// Values returned by the iterator are returned in ascending order:
-    ///
-    /// ```
-    /// use std::collections::BTreeSet;
-    ///
     /// let set = BTreeSet::from([3, 1, 2]);
     /// let mut set_iter = set.iter();
     /// assert_eq!(set_iter.next(), Some(&1));
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index bf01b2082ed..60b07485c3a 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2719,7 +2719,7 @@ impl<T> Weak<T> {
     /// ```
     #[inline]
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
+    #[rustc_const_stable(feature = "const_weak_new", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     pub const fn new() -> Weak<T> {
         Weak {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index c2202f2fce5..6c701225a84 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2503,7 +2503,7 @@ impl<T> Weak<T> {
     /// ```
     #[inline]
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
+    #[rustc_const_stable(feature = "const_weak_new", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     pub const fn new() -> Weak<T> {
         Weak {
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1b24c637550..e45ddc7896b 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -213,7 +213,7 @@ mod spec_extend;
 ///
 /// # Indexing
 ///
-/// The `Vec` type allows to access values by index, because it implements the
+/// The `Vec` type allows access to values by index, because it implements the
 /// [`Index`] trait. An example will be more explicit:
 ///
 /// ```
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index 17d56d491d9..711e4eef2e7 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -368,29 +368,73 @@ fn remove_bad() {
 
 #[test]
 fn test_remove_matches() {
+    // test_single_pattern_occurrence
     let mut s = "abc".to_string();
-
     s.remove_matches('b');
     assert_eq!(s, "ac");
+    // repeat_test_single_pattern_occurrence
     s.remove_matches('b');
     assert_eq!(s, "ac");
 
+    // test_single_character_pattern
     let mut s = "abcb".to_string();
-
     s.remove_matches('b');
     assert_eq!(s, "ac");
 
+    // test_pattern_with_special_characters
     let mut s = "ศไทย中华Việt Nam; foobarศ".to_string();
     s.remove_matches('ศ');
     assert_eq!(s, "ไทย中华Việt Nam; foobar");
 
+    // test_pattern_empty_text_and_pattern
     let mut s = "".to_string();
     s.remove_matches("");
     assert_eq!(s, "");
 
+    // test_pattern_empty_text
+    let mut s = "".to_string();
+    s.remove_matches("something");
+    assert_eq!(s, "");
+
+    // test_empty_pattern
+    let mut s = "Testing with empty pattern.".to_string();
+    s.remove_matches("");
+    assert_eq!(s, "Testing with empty pattern.");
+
+    // test_multiple_consecutive_patterns_1
     let mut s = "aaaaa".to_string();
     s.remove_matches('a');
     assert_eq!(s, "");
+
+    // test_multiple_consecutive_patterns_2
+    let mut s = "Hello **world****today!**".to_string();
+    s.remove_matches("**");
+    assert_eq!(s, "Hello worldtoday!");
+
+    // test_case_insensitive_pattern
+    let mut s = "CASE ** SeNsItIvE ** PaTtErN.".to_string();
+    s.remove_matches("sEnSiTiVe");
+    assert_eq!(s, "CASE ** SeNsItIvE ** PaTtErN.");
+
+    // test_pattern_with_digits
+    let mut s = "123 ** 456 ** 789".to_string();
+    s.remove_matches("**");
+    assert_eq!(s, "123  456  789");
+
+    // test_pattern_occurs_after_empty_string
+    let mut s = "abc X defXghi".to_string();
+    s.remove_matches("X");
+    assert_eq!(s, "abc  defghi");
+
+    // test_large_pattern
+    let mut s = "aaaXbbbXcccXdddXeee".to_string();
+    s.remove_matches("X");
+    assert_eq!(s, "aaabbbcccdddeee");
+
+    // test_pattern_at_multiple_positions
+    let mut s = "Pattern ** found ** multiple ** times ** in ** text.".to_string();
+    s.remove_matches("**");
+    assert_eq!(s, "Pattern  found  multiple  times  in  text.");
 }
 
 #[test]
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 5f06a7b0795..2e8534f651a 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -250,10 +250,12 @@ impl<T> Default for OnceCell<T> {
 #[stable(feature = "once_cell", since = "1.70.0")]
 impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_tuple("OnceCell");
         match self.get() {
-            Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
-            None => f.write_str("OnceCell(Uninit)"),
-        }
+            Some(v) => d.field(v),
+            None => d.field(&format_args!("<uninit>")),
+        };
+        d.finish()
     }
 }
 
diff --git a/library/core/src/error.md b/library/core/src/error.md
index 78808d489b2..7771b8adc92 100644
--- a/library/core/src/error.md
+++ b/library/core/src/error.md
@@ -93,7 +93,8 @@ information that is already communicated by the source error being
 unwrapped:
 
 ```text
-thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6
+thread 'main' panicked at src/main.rs:4:6:
+env variable `IMPORTANT_PATH` is not set: NotPresent
 ```
 
 In this example we end up mentioning that an env variable is not set,
@@ -109,7 +110,8 @@ prevent the source error, we end up introducing new information that is
 independent from our source error.
 
 ```text
-thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6
+thread 'main' panicked at src/main.rs:4:6:
+env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent
 ```
 
 In this example we are communicating not only the name of the
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 1786b309c5b..9ce6093f1d1 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2521,22 +2521,12 @@ impl<T: Copy + Debug> Debug for Cell<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Debug> Debug for RefCell<T> {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        let mut d = f.debug_struct("RefCell");
         match self.try_borrow() {
-            Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(),
-            Err(_) => {
-                // The RefCell is mutably borrowed so we can't look at its value
-                // here. Show a placeholder instead.
-                struct BorrowedPlaceholder;
-
-                impl Debug for BorrowedPlaceholder {
-                    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-                        f.write_str("<borrowed>")
-                    }
-                }
-
-                f.debug_struct("RefCell").field("value", &BorrowedPlaceholder).finish()
-            }
-        }
+            Ok(borrow) => d.field("value", &borrow),
+            Err(_) => d.field("value", &format_args!("<borrowed>")),
+        };
+        d.finish()
     }
 }
 
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9b6ff76b240..1020e655579 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1125,6 +1125,7 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "if you don't need the returned value, use `if let` instead"]
     pub fn map_or<U, F>(self, default: U, f: F) -> U
     where
         F: FnOnce(T) -> U,
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 5576adde84b..c7f04f11ef6 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -147,16 +147,18 @@ impl<'a> PanicInfo<'a> {
 impl fmt::Display for PanicInfo<'_> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         formatter.write_str("panicked at ")?;
+        self.location.fmt(formatter)?;
         if let Some(message) = self.message {
-            write!(formatter, "'{}', ", message)?
+            formatter.write_str(":\n")?;
+            formatter.write_fmt(*message)?;
         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
-            write!(formatter, "'{}', ", payload)?
+            formatter.write_str(":\n")?;
+            formatter.write_str(payload)?;
         }
         // NOTE: we cannot use downcast_ref::<String>() here
         // since String is not available in core!
         // The payload is a String when `std::panic!` is called with multiple arguments,
         // but in that case the message is also available.
-
-        self.location.fmt(formatter)
+        Ok(())
     }
 }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index a8074c8659b..9582ca9e0be 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -367,13 +367,14 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// [the module documentation]: crate::ptr#safety
     #[stable(feature = "nonnull", since = "1.25.0")]
-    #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+    #[rustc_const_stable(feature = "const_nonnull_as_ref", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline(always)]
     pub const unsafe fn as_ref<'a>(&self) -> &'a T {
         // SAFETY: the caller must guarantee that `self` meets all the
         // requirements for a reference.
-        unsafe { &*self.as_ptr() }
+        // `cast_const` avoids a mutable raw pointer deref.
+        unsafe { &*self.as_ptr().cast_const() }
     }
 
     /// Returns a unique reference to the value. If the value may be uninitialized, [`as_uninit_mut`]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 51b7616ffec..6981abc9be1 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -768,6 +768,7 @@ impl<T, E> Result<T, E> {
     /// ```
     #[inline]
     #[stable(feature = "result_map_or", since = "1.41.0")]
+    #[must_use = "if you don't need the returned value, use `if let` instead"]
     pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
         match self {
             Ok(t) => f(t),
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index e1e3bcc05e7..d313e8e012f 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -727,7 +727,7 @@ where
 }
 
 /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
-fn into_range_unchecked(
+pub(crate) fn into_range_unchecked(
     len: usize,
     (start, end): (ops::Bound<usize>, ops::Bound<usize>),
 ) -> ops::Range<usize> {
@@ -747,7 +747,7 @@ fn into_range_unchecked(
 
 /// Convert pair of `ops::Bound`s into `ops::Range`.
 /// Returns `None` on overflowing indices.
-fn into_range(
+pub(crate) fn into_range(
     len: usize,
     (start, end): (ops::Bound<usize>, ops::Bound<usize>),
 ) -> Option<ops::Range<usize>> {
@@ -772,7 +772,7 @@ fn into_range(
 
 /// Convert pair of `ops::Bound`s into `ops::Range`.
 /// Panics on overflowing indices.
-fn into_slice_range(
+pub(crate) fn into_slice_range(
     len: usize,
     (start, end): (ops::Bound<usize>, ops::Bound<usize>),
 ) -> ops::Range<usize> {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4f13ea9790d..d95662afddd 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -38,7 +38,7 @@ pub mod sort;
 
 mod ascii;
 mod cmp;
-mod index;
+pub(crate) mod index;
 mod iter;
 mod raw;
 mod rotate;
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 07a5990e595..71c03f7bfc5 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -952,6 +952,10 @@ impl str {
     ///
     /// Line terminators are not included in the lines returned by the iterator.
     ///
+    /// Note that any carriage return (`\r`) not immediately followed by a
+    /// line feed (`\n`) does not split a line. These carriage returns are
+    /// thereby included in the produced lines.
+    ///
     /// The final line ending is optional. A string that ends with a final line
     /// ending will return the same lines as an otherwise identical string
     /// without a final line ending.
@@ -961,18 +965,19 @@ impl str {
     /// Basic usage:
     ///
     /// ```
-    /// let text = "foo\r\nbar\n\nbaz\n";
+    /// let text = "foo\r\nbar\n\nbaz\r";
     /// let mut lines = text.lines();
     ///
     /// assert_eq!(Some("foo"), lines.next());
     /// assert_eq!(Some("bar"), lines.next());
     /// assert_eq!(Some(""), lines.next());
-    /// assert_eq!(Some("baz"), lines.next());
+    /// // Trailing carriage return is included in the last line
+    /// assert_eq!(Some("baz\r"), lines.next());
     ///
     /// assert_eq!(None, lines.next());
     /// ```
     ///
-    /// The final line ending isn't required:
+    /// The final line does not require any ending:
     ///
     /// ```
     /// let text = "foo\nbar\n\r\nbaz";
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 1d52335f28e..49f9f6d4ad1 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -252,6 +252,58 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
     }
 }
 
+/// Implements substring slicing for arbitrary bounds.
+///
+/// Returns a slice of the given string bounded by the byte indices
+/// provided by each bound.
+///
+/// This operation is *O*(1).
+///
+/// # Panics
+///
+/// Panics if `begin` or `end` (if it exists and once adjusted for
+/// inclusion/exclusion) does not point to the starting byte offset of
+/// a character (as defined by `is_char_boundary`), if `begin > end`, or if
+/// `end > len`.
+#[stable(feature = "slice_index_str_with_ops_bound_pair", since = "CURRENT_RUSTC_VERSION")]
+unsafe impl SliceIndex<str> for (ops::Bound<usize>, ops::Bound<usize>) {
+    type Output = str;
+
+    #[inline]
+    fn get(self, slice: &str) -> Option<&str> {
+        crate::slice::index::into_range(slice.len(), self)?.get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut str> {
+        crate::slice::index::into_range(slice.len(), self)?.get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const str {
+        let len = (slice as *const [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut str {
+        let len = (slice as *mut [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &str) -> &str {
+        crate::slice::index::into_slice_range(slice.len(), self).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut str {
+        crate::slice::index::into_slice_range(slice.len(), self).index_mut(slice)
+    }
+}
+
 /// Implements substring slicing with syntax `&self[.. end]` or `&mut
 /// self[.. end]`.
 ///
diff --git a/library/portable-simd/crates/core_simd/examples/dot_product.rs b/library/portable-simd/crates/core_simd/examples/dot_product.rs
index 391f08f55a0..a7973ec7404 100644
--- a/library/portable-simd/crates/core_simd/examples/dot_product.rs
+++ b/library/portable-simd/crates/core_simd/examples/dot_product.rs
@@ -130,7 +130,7 @@ pub fn dot_prod_simd_4(a: &[f32], b: &[f32]) -> f32 {
 }
 
 // This version allocates a single `XMM` register for accumulation, and the folds don't allocate on top of that.
-// Notice the the use of `mul_add`, which can do a multiply and an add operation ber iteration.
+// Notice the use of `mul_add`, which can do a multiply and an add operation ber iteration.
 pub fn dot_prod_simd_5(a: &[f32], b: &[f32]) -> f32 {
     a.array_chunks::<4>()
         .map(|&a| f32x4::from_array(a))
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 7543ffadd41..e7110aebdea 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -89,12 +89,12 @@ mod tests;
 // a backtrace or actually symbolizing it.
 
 use crate::backtrace_rs::{self, BytesOrWideString};
-use crate::cell::UnsafeCell;
 use crate::env;
 use crate::ffi::c_void;
 use crate::fmt;
+use crate::panic::UnwindSafe;
 use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-use crate::sync::Once;
+use crate::sync::LazyLock;
 use crate::sys_common::backtrace::{lock, output_filename};
 use crate::vec::Vec;
 
@@ -133,12 +133,11 @@ pub enum BacktraceStatus {
 enum Inner {
     Unsupported,
     Disabled,
-    Captured(LazilyResolvedCapture),
+    Captured(LazyLock<Capture, LazyResolve>),
 }
 
 struct Capture {
     actual_start: usize,
-    resolved: bool,
     frames: Vec<BacktraceFrame>,
 }
 
@@ -179,7 +178,7 @@ impl fmt::Debug for Backtrace {
         let capture = match &self.inner {
             Inner::Unsupported => return fmt.write_str("<unsupported>"),
             Inner::Disabled => return fmt.write_str("<disabled>"),
-            Inner::Captured(c) => c.force(),
+            Inner::Captured(c) => &**c,
         };
 
         let frames = &capture.frames[capture.actual_start..];
@@ -347,11 +346,10 @@ impl Backtrace {
         let inner = if frames.is_empty() {
             Inner::Unsupported
         } else {
-            Inner::Captured(LazilyResolvedCapture::new(Capture {
+            Inner::Captured(LazyLock::new(lazy_resolve(Capture {
                 actual_start: actual_start.unwrap_or(0),
                 frames,
-                resolved: false,
-            }))
+            })))
         };
 
         Backtrace { inner }
@@ -376,7 +374,7 @@ impl<'a> Backtrace {
     #[must_use]
     #[unstable(feature = "backtrace_frames", issue = "79676")]
     pub fn frames(&'a self) -> &'a [BacktraceFrame] {
-        if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
+        if let Inner::Captured(c) = &self.inner { &c.frames } else { &[] }
     }
 }
 
@@ -386,7 +384,7 @@ impl fmt::Display for Backtrace {
         let capture = match &self.inner {
             Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
             Inner::Disabled => return fmt.write_str("disabled backtrace"),
-            Inner::Captured(c) => c.force(),
+            Inner::Captured(c) => &**c,
         };
 
         let full = fmt.alternate();
@@ -430,46 +428,15 @@ impl fmt::Display for Backtrace {
     }
 }
 
-struct LazilyResolvedCapture {
-    sync: Once,
-    capture: UnsafeCell<Capture>,
-}
-
-impl LazilyResolvedCapture {
-    fn new(capture: Capture) -> Self {
-        LazilyResolvedCapture { sync: Once::new(), capture: UnsafeCell::new(capture) }
-    }
-
-    fn force(&self) -> &Capture {
-        self.sync.call_once(|| {
-            // SAFETY: This exclusive reference can't overlap with any others
-            // `Once` guarantees callers will block until this closure returns
-            // `Once` also guarantees only a single caller will enter this closure
-            unsafe { &mut *self.capture.get() }.resolve();
-        });
-
-        // SAFETY: This shared reference can't overlap with the exclusive reference above
-        unsafe { &*self.capture.get() }
-    }
-}
-
-// SAFETY: Access to the inner value is synchronized using a thread-safe `Once`
-// So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
-unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
-
-impl Capture {
-    fn resolve(&mut self) {
-        // If we're already resolved, nothing to do!
-        if self.resolved {
-            return;
-        }
-        self.resolved = true;
+type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe;
 
+fn lazy_resolve(mut capture: Capture) -> LazyResolve {
+    move || {
         // Use the global backtrace lock to synchronize this as it's a
         // requirement of the `backtrace` crate, and then actually resolve
         // everything.
         let _lock = lock();
-        for frame in self.frames.iter_mut() {
+        for frame in capture.frames.iter_mut() {
             let symbols = &mut frame.symbols;
             let frame = match &frame.frame {
                 RawFrame::Actual(frame) => frame,
@@ -490,6 +457,8 @@ impl Capture {
                 });
             }
         }
+
+        capture
     }
 }
 
diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs
index 4dfbf88e83e..73543a3af54 100644
--- a/library/std/src/backtrace/tests.rs
+++ b/library/std/src/backtrace/tests.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
 
 fn generate_fake_frames() -> Vec<BacktraceFrame> {
     vec![
@@ -43,9 +44,8 @@ fn generate_fake_frames() -> Vec<BacktraceFrame> {
 #[test]
 fn test_debug() {
     let backtrace = Backtrace {
-        inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
+        inner: Inner::Captured(LazyLock::preinit(Capture {
             actual_start: 1,
-            resolved: true,
             frames: generate_fake_frames(),
         })),
     };
@@ -66,9 +66,8 @@ fn test_debug() {
 #[test]
 fn test_frames() {
     let backtrace = Backtrace {
-        inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
+        inner: Inner::Captured(LazyLock::preinit(Capture {
             actual_start: 1,
-            resolved: true,
             frames: generate_fake_frames(),
         })),
     };
@@ -93,3 +92,9 @@ fn test_frames() {
 
     assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
 }
+
+#[test]
+fn backtrace_unwind_safe() {
+    fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
+    assert_unwind_safe::<Backtrace>();
+}
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 05f8fd8de32..ee5eddebfaf 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -121,7 +121,8 @@ mod private {
 /// This example produces the following output:
 ///
 /// ```console
-/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
+/// thread 'main' panicked at src/error.rs:34:40:
+/// called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!
 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 /// ```
 ///
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 3ddb8748753..b0484474712 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -156,6 +156,8 @@
 
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
+#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+pub use core::ffi::FromBytesUntilNulError;
 #[stable(feature = "core_c_str", since = "1.64.0")]
 pub use core::ffi::{CStr, FromBytesWithNulError};
 
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index f076ee0923c..3840ffe7eec 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -8,24 +8,41 @@ use crate::io::{
     self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
 };
 
-/// A reader which is always at EOF.
+/// `Empty` ignores any data written via [`Write`], and will always be empty
+/// (returning zero bytes) when read via [`Read`].
 ///
-/// This struct is generally created by calling [`empty()`]. Please see
-/// the documentation of [`empty()`] for more details.
+/// This struct is generally created by calling [`empty()`]. Please
+/// see the documentation of [`empty()`] for more details.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[non_exhaustive]
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Debug, Default)]
 pub struct Empty;
 
-/// Constructs a new handle to an empty reader.
+/// Creates a value that is always at EOF for reads, and ignores all data written.
 ///
-/// All reads from the returned reader will return <code>[Ok]\(0)</code>.
+/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
+/// and the contents of the buffer will not be inspected.
+///
+/// All calls to [`read`] from the returned reader will return [`Ok(0)`].
+///
+/// [`Ok(buf.len())`]: Ok
+/// [`Ok(0)`]: Ok
+///
+/// [`write`]: Write::write
+/// [`read`]: Read::read
 ///
 /// # Examples
 ///
-/// A slightly sad example of not reading anything into a buffer:
+/// ```rust
+/// use std::io::{self, Write};
 ///
+/// let buffer = vec![1, 2, 3, 5, 8];
+/// let num_bytes = io::empty().write(&buffer).unwrap();
+/// assert_eq!(num_bytes, 5);
 /// ```
+///
+///
+/// ```rust
 /// use std::io::{self, Read};
 ///
 /// let mut buffer = String::new();
@@ -76,13 +93,6 @@ impl Seek for Empty {
     }
 }
 
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for Empty {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Empty").finish_non_exhaustive()
-    }
-}
-
 impl SizeHint for Empty {
     #[inline]
     fn upper_bound(&self) -> Option<usize> {
@@ -90,6 +100,54 @@ impl SizeHint for Empty {
     }
 }
 
+#[stable(feature = "empty_write", since = "CURRENT_RUSTC_VERSION")]
+impl Write for Empty {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum();
+        Ok(total_len)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[stable(feature = "empty_write", since = "CURRENT_RUSTC_VERSION")]
+impl Write for &Empty {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum();
+        Ok(total_len)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
 /// A reader which yields one byte over and over and over and over and over and...
 ///
 /// This struct is generally created by calling [`repeat()`]. Please
@@ -182,19 +240,20 @@ impl fmt::Debug for Repeat {
 
 /// A writer which will move data into the void.
 ///
-/// This struct is generally created by calling [`sink`]. Please
+/// This struct is generally created by calling [`sink()`]. Please
 /// see the documentation of [`sink()`] for more details.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[non_exhaustive]
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Debug, Default)]
 pub struct Sink;
 
 /// Creates an instance of a writer which will successfully consume all data.
 ///
-/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
+/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
 /// and the contents of the buffer will not be inspected.
 ///
 /// [`write`]: Write::write
+/// [`Ok(buf.len())`]: Ok
 ///
 /// # Examples
 ///
@@ -259,10 +318,3 @@ impl Write for &Sink {
         Ok(())
     }
 }
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for Sink {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Sink").finish_non_exhaustive()
-    }
-}
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 1baa94e64c9..6de91e29c77 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -18,7 +18,7 @@ fn empty_reads() {
     assert_eq!(e.read(&mut []).unwrap(), 0);
     assert_eq!(e.read(&mut [0]).unwrap(), 0);
     assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
-    assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+    assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0);
 
     let buf: &mut [MaybeUninit<_>] = &mut [];
     let mut buf: BorrowedBuf<'_> = buf.into();
@@ -40,7 +40,7 @@ fn empty_reads() {
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
     let mut buf: BorrowedBuf<'_> = buf.into();
-    e.by_ref().read_buf(buf.unfilled()).unwrap();
+    Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
     assert_eq!(buf.init_len(), 0);
 }
@@ -66,6 +66,15 @@ fn empty_seeks() {
 }
 
 #[test]
+fn empty_sinks() {
+    let mut e = empty();
+    assert_eq!(e.write(&[]).unwrap(), 0);
+    assert_eq!(e.write(&[0]).unwrap(), 1);
+    assert_eq!(e.write(&[0; 1024]).unwrap(), 1024);
+    assert_eq!(Write::by_ref(&mut e).write(&[0; 1024]).unwrap(), 1024);
+}
+
+#[test]
 fn repeat_repeats() {
     let mut r = repeat(4);
     let mut b = [0; 1024];
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 4cd251d0ac2..238c74229cc 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -272,6 +272,7 @@
 #![feature(staged_api)]
 #![feature(thread_local)]
 #![feature(try_blocks)]
+#![feature(type_alias_impl_trait)]
 #![feature(utf8_chunks)]
 // tidy-alphabetical-end
 //
diff --git a/library/std/src/os/android/raw.rs b/library/std/src/os/android/raw.rs
index daaf3d3eac6..175f8eac971 100644
--- a/library/std/src/os/android/raw.rs
+++ b/library/std/src/os/android/raw.rs
@@ -89,7 +89,7 @@ mod arch {
     }
 }
 
-#[cfg(target_arch = "aarch64")]
+#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
 mod arch {
     use crate::os::raw::{c_int, c_long, c_uint, c_ulong};
     use crate::os::unix::raw::{gid_t, uid_t};
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 15285465c71..6ff7b19f293 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -266,7 +266,7 @@ pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write, backtrace: Option<BacktraceStyle>| {
-        let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
+        let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}");
 
         static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index 76a1b4a2a86..9c4b926b7ec 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -21,11 +21,11 @@ impl WaitTimeoutResult {
     ///
     /// # Examples
     ///
-    /// This example spawns a thread which will update the boolean value and
-    /// then wait 100 milliseconds before notifying the condvar.
+    /// This example spawns a thread which will sleep 20 milliseconds before
+    /// updating a boolean value and then notifying the condvar.
     ///
-    /// The main thread will wait with a timeout on the condvar and then leave
-    /// once the boolean has been updated and notified.
+    /// The main thread will wait with a 10 millisecond timeout on the condvar
+    /// and will leave the loop upon timeout.
     ///
     /// ```
     /// use std::sync::{Arc, Condvar, Mutex};
@@ -49,14 +49,12 @@ impl WaitTimeoutResult {
     ///
     /// // Wait for the thread to start up.
     /// let (lock, cvar) = &*pair;
-    /// let mut started = lock.lock().unwrap();
     /// loop {
     ///     // Let's put a timeout on the condvar's wait.
-    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
-    ///     // 10 milliseconds have passed, or maybe the value changed!
-    ///     started = result.0;
-    ///     if *started == true {
-    ///         // We received the notification and the value has been updated, we can leave.
+    ///     let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap();
+    ///     // 10 milliseconds have passed.
+    ///     if result.1.timed_out() {
+    ///         // timed out now and we can leave.
     ///         break
     ///     }
     /// }
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 37bdec5abcc..3598598cfa0 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -89,6 +89,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
         LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
     }
 
+    /// Creates a new lazy value that is already initialized.
+    #[inline]
+    #[cfg(test)]
+    pub(crate) fn preinit(value: T) -> LazyLock<T, F> {
+        let once = Once::new();
+        once.call_once(|| {});
+        LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
+    }
+
     /// Consumes this `LazyLock` returning the stored value.
     ///
     /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
@@ -213,10 +222,12 @@ impl<T: Default> Default for LazyLock<T> {
 #[unstable(feature = "lazy_cell", issue = "109736")]
 impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_tuple("LazyLock");
         match self.get() {
-            Some(v) => f.debug_tuple("LazyLock").field(v).finish(),
-            None => f.write_str("LazyLock(Uninit)"),
-        }
+            Some(v) => d.field(v),
+            None => d.field(&format_args!("<uninit>")),
+        };
+        d.finish()
     }
 }
 
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index b8fec6902a0..b4ae6b7e07e 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -490,13 +490,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
                 d.field("data", &&**err.get_ref());
             }
             Err(TryLockError::WouldBlock) => {
-                struct LockedPlaceholder;
-                impl fmt::Debug for LockedPlaceholder {
-                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        f.write_str("<locked>")
-                    }
-                }
-                d.field("data", &LockedPlaceholder);
+                d.field("data", &format_args!("<locked>"));
             }
         }
         d.field("poisoned", &self.poison.get());
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index e83bc35ee98..e2b7b893cb5 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -365,10 +365,12 @@ impl<T> Default for OnceLock<T> {
 #[stable(feature = "once_cell", since = "1.70.0")]
 impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_tuple("OnceLock");
         match self.get() {
-            Some(v) => f.debug_tuple("Once").field(v).finish(),
-            None => f.write_str("Once(Uninit)"),
-        }
+            Some(v) => d.field(v),
+            None => d.field(&format_args!("<uninit>")),
+        };
+        d.finish()
     }
 }
 
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 7c409cb3e97..26aaa2414c9 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -485,13 +485,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
                 d.field("data", &&**err.get_ref());
             }
             Err(TryLockError::WouldBlock) => {
-                struct LockedPlaceholder;
-                impl fmt::Debug for LockedPlaceholder {
-                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        f.write_str("<locked>")
-                    }
-                }
-                d.field("data", &LockedPlaceholder);
+                d.field("data", &format_args!("<locked>"));
             }
         }
         d.field("poisoned", &self.poison.get());
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 6f020940df1..84e2c5d8d7f 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -60,6 +60,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
     bt_fmt.add_context()?;
     let mut idx = 0;
     let mut res = Ok(());
+    let mut omitted_count: usize = 0;
+    let mut first_omit = true;
     // Start immediately if we're not using a short backtrace.
     let mut start = print_fmt != PrintFmt::Short;
     backtrace_rs::trace_unsynchronized(|frame| {
@@ -85,10 +87,27 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                         start = true;
                         return;
                     }
+                    if !start {
+                        omitted_count += 1;
+                    }
                 }
             }
 
             if start {
+                if omitted_count > 0 {
+                    debug_assert!(print_fmt == PrintFmt::Short);
+                    // only print the message between the middle of frames
+                    if !first_omit {
+                        let _ = writeln!(
+                            bt_fmt.formatter(),
+                            "      [... omitted {} frame{} ...]",
+                            omitted_count,
+                            if omitted_count > 1 { "s" } else { "" }
+                        );
+                    }
+                    first_omit = false;
+                    omitted_count = 0;
+                }
                 res = bt_fmt.frame().symbol(frame, symbol);
             }
         });
diff --git a/library/test/src/types.rs b/library/test/src/types.rs
index 504ceee7fce..1a8ae889c8c 100644
--- a/library/test/src/types.rs
+++ b/library/test/src/types.rs
@@ -224,7 +224,7 @@ impl TestDesc {
         }
     }
 
-    /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test.
+    /// Returns None for ignored test or tests that are just run, otherwise returns a description of the type of test.
     /// Descriptions include "should panic", "compile fail" and "compile".
     pub fn test_mode(&self) -> Option<&'static str> {
         if self.ignore {
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index 30dfa81c6f7..c497cabbd69 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -67,7 +67,7 @@ fn main() {
             `cp config.example.toml config.toml`"
         );
     } else if let Some(suggestion) = &changelog_suggestion {
-        println!("{}", suggestion);
+        println!("{suggestion}");
     }
 
     let pre_commit = config.src.join(".git").join("hooks").join("pre-commit");
@@ -80,7 +80,7 @@ fn main() {
             `cp config.example.toml config.toml`"
         );
     } else if let Some(suggestion) = &changelog_suggestion {
-        println!("{}", suggestion);
+        println!("{suggestion}");
     }
 
     // Give a warning if the pre-commit script is in pre-commit and not pre-push.
@@ -107,13 +107,13 @@ fn check_version(config: &Config) -> Option<String> {
     let suggestion = if let Some(seen) = config.changelog_seen {
         if seen != VERSION {
             msg.push_str("warning: there have been changes to x.py since you last updated.\n");
-            format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION)
+            format!("update `config.toml` to use `changelog-seen = {VERSION}` instead")
         } else {
             return None;
         }
     } else {
         msg.push_str("warning: x.py has made several changes recently you may want to look at\n");
-        format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION)
+        format!("add `changelog-seen = {VERSION}` at the top of `config.toml`")
     };
 
     msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n");
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index e87125a49a6..10718aeb89f 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -120,7 +120,7 @@ fn main() {
 
         // Override linker if necessary.
         if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
-            cmd.arg(format!("-Clinker={}", host_linker));
+            cmd.arg(format!("-Clinker={host_linker}"));
         }
         if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
             cmd.arg("-Clink-args=-fuse-ld=lld");
@@ -206,11 +206,11 @@ fn main() {
             env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
         let prefix = if is_test { "[RUSTC-SHIM] rustc --test" } else { "[RUSTC-SHIM] rustc" };
         let prefix = match crate_name {
-            Some(crate_name) => format!("{} {}", prefix, crate_name),
+            Some(crate_name) => format!("{prefix} {crate_name}"),
             None => prefix.to_string(),
         };
         for (i, (k, v)) in rust_env_vars.enumerate() {
-            eprintln!("{} env[{}]: {:?}={:?}", prefix, i, k, v);
+            eprintln!("{prefix} env[{i}]: {k:?}={v:?}");
         }
         eprintln!("{} working directory: {}", prefix, env::current_dir().unwrap().display());
         eprintln!(
@@ -220,13 +220,13 @@ fn main() {
             env::join_paths(&dylib_path).unwrap(),
             cmd,
         );
-        eprintln!("{} sysroot: {:?}", prefix, sysroot);
-        eprintln!("{} libdir: {:?}", prefix, libdir);
+        eprintln!("{prefix} sysroot: {sysroot:?}");
+        eprintln!("{prefix} libdir: {libdir:?}");
     }
 
     let start = Instant::now();
     let (child, status) = {
-        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
+        let errmsg = format!("\nFailed to run:\n{cmd:?}\n-------------");
         let mut child = cmd.spawn().expect(&errmsg);
         let status = child.wait().expect(&errmsg);
         (child, status)
@@ -259,7 +259,7 @@ fn main() {
         // should run on success, after this block.
     }
     if verbose > 0 {
-        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
+        println!("\nDid not run successfully: {status}\n{cmd:?}\n-------------");
     }
 
     if let Some(mut on_fail) = on_fail {
@@ -271,7 +271,7 @@ fn main() {
     match status.code() {
         Some(i) => std::process::exit(i),
         None => {
-            eprintln!("rustc exited with {}", status);
+            eprintln!("rustc exited with {status}");
             std::process::exit(0xfe);
         }
     }
@@ -396,21 +396,20 @@ fn format_rusage_data(_child: Child) -> Option<String> {
     let minflt = rusage.ru_minflt;
     let majflt = rusage.ru_majflt;
     if minflt != 0 || majflt != 0 {
-        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
+        init_str.push_str(&format!(" page reclaims: {minflt} page faults: {majflt}"));
     }
 
     let inblock = rusage.ru_inblock;
     let oublock = rusage.ru_oublock;
     if inblock != 0 || oublock != 0 {
-        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
+        init_str.push_str(&format!(" fs block inputs: {inblock} fs block outputs: {oublock}"));
     }
 
     let nvcsw = rusage.ru_nvcsw;
     let nivcsw = rusage.ru_nivcsw;
     if nvcsw != 0 || nivcsw != 0 {
         init_str.push_str(&format!(
-            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
-            nvcsw, nivcsw
+            " voluntary ctxt switches: {nvcsw} involuntary ctxt switches: {nivcsw}"
         ));
     }
 
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index d2b85f7a629..4ecb3349816 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -62,7 +62,7 @@ fn main() {
     }
     if let Ok(no_threads) = env::var("RUSTDOC_LLD_NO_THREADS") {
         cmd.arg("-Clink-arg=-fuse-ld=lld");
-        cmd.arg(format!("-Clink-arg=-Wl,{}", no_threads));
+        cmd.arg(format!("-Clink-arg=-Wl,{no_threads}"));
     }
     // Cargo doesn't pass RUSTDOCFLAGS to proc_macros:
     // https://github.com/rust-lang/cargo/issues/4423
@@ -82,12 +82,12 @@ fn main() {
             env::join_paths(&dylib_path).unwrap(),
             cmd,
         );
-        eprintln!("sysroot: {:?}", sysroot);
-        eprintln!("libdir: {:?}", libdir);
+        eprintln!("sysroot: {sysroot:?}");
+        eprintln!("libdir: {libdir:?}");
     }
 
     std::process::exit(match cmd.status() {
         Ok(s) => s.code().unwrap_or(1),
-        Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+        Err(e) => panic!("\n\nfailed to run {cmd:?}: {e}\n\n"),
     })
 }
diff --git a/src/bootstrap/bolt.rs b/src/bootstrap/bolt.rs
deleted file mode 100644
index 017c4602d43..00000000000
--- a/src/bootstrap/bolt.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use std::path::Path;
-use std::process::Command;
-
-/// Uses the `llvm-bolt` binary to instrument the artifact at the given `path` with BOLT.
-/// When the instrumented artifact is executed, it will generate BOLT profiles into
-/// `/tmp/prof.fdata.<pid>.fdata`.
-/// Creates the instrumented artifact at `output_path`.
-pub fn instrument_with_bolt(path: &Path, output_path: &Path) {
-    let status = Command::new("llvm-bolt")
-        .arg("-instrument")
-        .arg(&path)
-        // Make sure that each process will write its profiles into a separate file
-        .arg("--instrumentation-file-append-pid")
-        .arg("-o")
-        .arg(output_path)
-        .status()
-        .expect("Could not instrument artifact using BOLT");
-
-    if !status.success() {
-        panic!("Could not instrument {} with BOLT, exit code {:?}", path.display(), status.code());
-    }
-}
-
-/// Uses the `llvm-bolt` binary to optimize the artifact at the given `path` with BOLT,
-/// using merged profiles from `profile_path`.
-///
-/// The recorded profiles have to be merged using the `merge-fdata` tool from LLVM and the merged
-/// profile path should be then passed to this function.
-///
-/// Creates the optimized artifact at `output_path`.
-pub fn optimize_with_bolt(path: &Path, profile_path: &Path, output_path: &Path) {
-    let status = Command::new("llvm-bolt")
-        .arg(&path)
-        .arg("-data")
-        .arg(&profile_path)
-        .arg("-o")
-        .arg(output_path)
-        // Reorder basic blocks within functions
-        .arg("-reorder-blocks=ext-tsp")
-        // Reorder functions within the binary
-        .arg("-reorder-functions=hfsort+")
-        // Split function code into hot and code regions
-        .arg("-split-functions")
-        // Split as many basic blocks as possible
-        .arg("-split-all-cold")
-        // Move jump tables to a separate section
-        .arg("-jump-tables=move")
-        // Fold functions with identical code
-        .arg("-icf=1")
-        // Update DWARF debug info in the final binary
-        .arg("-update-debug-sections")
-        // Try to reuse old text segments to reduce binary size
-        .arg("--use-old-text")
-        // Print optimization statistics
-        .arg("-dyno-stats")
-        .status()
-        .expect("Could not optimize artifact using BOLT");
-
-    if !status.success() {
-        panic!("Could not optimize {} with BOLT, exit code {:?}", path.display(), status.code());
-    }
-}
diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs
index cd1f418028c..e0e32d31353 100644
--- a/src/bootstrap/build.rs
+++ b/src/bootstrap/build.rs
@@ -3,5 +3,5 @@ use std::env;
 fn main() {
     let host = env::var("HOST").unwrap();
     println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rustc-env=BUILD_TRIPLE={}", host);
+    println!("cargo:rustc-env=BUILD_TRIPLE={host}");
 }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 1707dafb11a..d369e8eeda9 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -319,7 +319,7 @@ impl StepDescription {
     fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
         if builder.config.exclude.iter().any(|e| pathset.has(&e, builder.kind)) {
             if !matches!(builder.config.dry_run, DryRun::SelfCheck) {
-                println!("Skipping {:?} because it is excluded", pathset);
+                println!("Skipping {pathset:?} because it is excluded");
             }
             return true;
         }
@@ -473,8 +473,7 @@ impl<'a> ShouldRun<'a> {
         // `compiler` and `library` folders respectively.
         assert!(
             self.kind == Kind::Setup || !self.builder.src.join(alias).exists(),
-            "use `builder.path()` for real paths: {}",
-            alias
+            "use `builder.path()` for real paths: {alias}"
         );
         self.paths.insert(PathSet::Set(
             std::iter::once(TaskPath { path: alias.into(), kind: Some(self.kind) }).collect(),
@@ -1283,7 +1282,7 @@ impl<'a> Builder<'a> {
                         out_dir.join(target.triple).join("doc")
                     }
                 }
-                _ => panic!("doc mode {:?} not expected", mode),
+                _ => panic!("doc mode {mode:?} not expected"),
             };
             let rustdoc = self.rustdoc(compiler);
             self.clear_if_dirty(&my_out, &rustdoc);
@@ -1637,15 +1636,15 @@ impl<'a> Builder<'a> {
                 // so. Note that this is definitely a hack, and we should likely
                 // flesh out rpath support more fully in the future.
                 rustflags.arg("-Zosx-rpath-install-name");
-                Some(format!("-Wl,-rpath,@loader_path/../{}", libdir))
+                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
             } else if !target.contains("windows") && !target.contains("aix") {
                 rustflags.arg("-Clink-args=-Wl,-z,origin");
-                Some(format!("-Wl,-rpath,$ORIGIN/../{}", libdir))
+                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
             } else {
                 None
             };
             if let Some(rpath) = rpath {
-                rustflags.arg(&format!("-Clink-args={}", rpath));
+                rustflags.arg(&format!("-Clink-args={rpath}"));
             }
         }
 
@@ -1659,7 +1658,7 @@ impl<'a> Builder<'a> {
 
         if let Some(target_linker) = self.linker(target) {
             let target = crate::envify(&target.triple);
-            cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
+            cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
         }
         if self.is_fuse_ld_lld(target) {
             rustflags.arg("-Clink-args=-fuse-ld=lld");
@@ -1895,24 +1894,24 @@ impl<'a> Builder<'a> {
             };
             let triple_underscored = target.triple.replace("-", "_");
             let cc = ccacheify(&self.cc(target));
-            cargo.env(format!("CC_{}", triple_underscored), &cc);
+            cargo.env(format!("CC_{triple_underscored}"), &cc);
 
             let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
-            cargo.env(format!("CFLAGS_{}", triple_underscored), &cflags);
+            cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags);
 
             if let Some(ar) = self.ar(target) {
                 let ranlib = format!("{} s", ar.display());
                 cargo
-                    .env(format!("AR_{}", triple_underscored), ar)
-                    .env(format!("RANLIB_{}", triple_underscored), ranlib);
+                    .env(format!("AR_{triple_underscored}"), ar)
+                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
             }
 
             if let Ok(cxx) = self.cxx(target) {
                 let cxx = ccacheify(&cxx);
                 let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
                 cargo
-                    .env(format!("CXX_{}", triple_underscored), &cxx)
-                    .env(format!("CXXFLAGS_{}", triple_underscored), cxxflags);
+                    .env(format!("CXX_{triple_underscored}"), &cxx)
+                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
             }
         }
 
@@ -2025,7 +2024,7 @@ impl<'a> Builder<'a> {
             if let Some(limit) = limit {
                 if stage == 0 || self.config.default_codegen_backend().unwrap_or_default() == "llvm"
                 {
-                    rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={}", limit));
+                    rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
                 }
             }
         }
@@ -2033,7 +2032,7 @@ impl<'a> Builder<'a> {
         if matches!(mode, Mode::Std) {
             if let Some(mir_opt_level) = self.config.rust_validate_mir_opts {
                 rustflags.arg("-Zvalidate-mir");
-                rustflags.arg(&format!("-Zmir-opt-level={}", mir_opt_level));
+                rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}"));
             }
             // Always enable inlining MIR when building the standard library.
             // Without this flag, MIR inlining is disabled when incremental compilation is enabled.
@@ -2065,9 +2064,9 @@ impl<'a> Builder<'a> {
                     continue;
                 }
                 let mut out = String::new();
-                out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
+                out += &format!("\n\nCycle in build detected when adding {step:?}\n");
                 for el in stack.iter().rev() {
-                    out += &format!("\t{:?}\n", el);
+                    out += &format!("\t{el:?}\n");
                 }
                 panic!("{}", out);
             }
@@ -2094,7 +2093,7 @@ impl<'a> Builder<'a> {
         };
 
         if self.config.print_step_timings && !self.config.dry_run() {
-            let step_string = format!("{:?}", step);
+            let step_string = format!("{step:?}");
             let brace_index = step_string.find("{").unwrap_or(0);
             let type_string = type_name::<S>();
             println!(
@@ -2174,7 +2173,7 @@ impl<'a> Builder<'a> {
         let path = path.as_ref();
         self.info(&format!("Opening doc {}", path.display()));
         if let Err(err) = opener::open(path) {
-            self.info(&format!("{}\n", err));
+            self.info(&format!("{err}\n"));
         }
     }
 }
diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs
index 5376c4ec9c3..53e4ff03431 100644
--- a/src/bootstrap/cache.rs
+++ b/src/bootstrap/cache.rs
@@ -75,7 +75,7 @@ where
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s: &U = &*self;
-        f.write_fmt(format_args!("{:?}", s))
+        f.write_fmt(format_args!("{s:?}"))
     }
 }
 
@@ -236,7 +236,7 @@ impl Cache {
             .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
             .downcast_mut::<HashMap<S, S::Output>>()
             .expect("invalid type mapped");
-        assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
+        assert!(!stepcache.contains_key(&step), "processing {step:?} a second time");
         stepcache.insert(step, value);
     }
 
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index ade3bfed11f..2496c2a9db5 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -196,7 +196,7 @@ fn set_compiler(
                 '0'..='6' => {}
                 _ => return,
             }
-            let alternative = format!("e{}", gnu_compiler);
+            let alternative = format!("e{gnu_compiler}");
             if Command::new(&alternative).output().is_ok() {
                 cfg.compiler(alternative);
             }
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 9795f22e2b5..2c51ed5408e 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -322,7 +322,7 @@ impl Step for CodegenBackend {
         );
         cargo
             .arg("--manifest-path")
-            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
+            .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
         rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
 
         let _guard = builder.msg_check(&backend, target);
@@ -525,5 +525,5 @@ fn codegen_backend_stamp(
 ) -> PathBuf {
     builder
         .cargo_out(compiler, Mode::Codegen, target)
-        .join(format!(".librustc_codegen_{}-check.stamp", backend))
+        .join(format!(".librustc_codegen_{backend}-check.stamp"))
 }
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs
index ea8334eaeb6..7389816b44c 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/clean.rs
@@ -26,10 +26,15 @@ impl Step for CleanAll {
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let Subcommand::Clean { all, .. } = builder.config.cmd else {
+        let Subcommand::Clean { all, stage } = builder.config.cmd else {
             unreachable!("wrong subcommand?")
         };
-        clean_default(builder.build, all)
+
+        if all && stage.is_some() {
+            panic!("--all and --stage can't be used at the same time for `x clean`");
+        }
+
+        clean(builder.build, all, stage)
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -86,35 +91,70 @@ clean_crate_tree! {
     Std, Mode::Std, "sysroot";
 }
 
-fn clean_default(build: &Build, all: bool) {
+fn clean(build: &Build, all: bool, stage: Option<u32>) {
     if build.config.dry_run() {
         return;
     }
 
     rm_rf("tmp".as_ref());
 
+    // Clean the entire build directory
     if all {
         rm_rf(&build.out);
-    } else {
-        rm_rf(&build.out.join("tmp"));
-        rm_rf(&build.out.join("dist"));
-        rm_rf(&build.out.join("bootstrap"));
-        rm_rf(&build.out.join("rustfmt.stamp"));
-
-        for host in &build.hosts {
-            let entries = match build.out.join(host.triple).read_dir() {
-                Ok(iter) => iter,
-                Err(_) => continue,
-            };
-
-            for entry in entries {
-                let entry = t!(entry);
-                if entry.file_name().to_str() == Some("llvm") {
-                    continue;
-                }
-                let path = t!(entry.path().canonicalize());
-                rm_rf(&path);
+        return;
+    }
+
+    // Clean the target stage artifacts
+    if let Some(stage) = stage {
+        clean_specific_stage(build, stage);
+        return;
+    }
+
+    // Follow the default behaviour
+    clean_default(build);
+}
+
+fn clean_specific_stage(build: &Build, stage: u32) {
+    for host in &build.hosts {
+        let entries = match build.out.join(host.triple).read_dir() {
+            Ok(iter) => iter,
+            Err(_) => continue,
+        };
+
+        for entry in entries {
+            let entry = t!(entry);
+            let stage_prefix = format!("stage{}", stage);
+
+            // if current entry is not related with the target stage, continue
+            if !entry.file_name().to_str().unwrap_or("").contains(&stage_prefix) {
+                continue;
+            }
+
+            let path = t!(entry.path().canonicalize());
+            rm_rf(&path);
+        }
+    }
+}
+
+fn clean_default(build: &Build) {
+    rm_rf(&build.out.join("tmp"));
+    rm_rf(&build.out.join("dist"));
+    rm_rf(&build.out.join("bootstrap"));
+    rm_rf(&build.out.join("rustfmt.stamp"));
+
+    for host in &build.hosts {
+        let entries = match build.out.join(host.triple).read_dir() {
+            Ok(iter) => iter,
+            Err(_) => continue,
+        };
+
+        for entry in entries {
+            let entry = t!(entry);
+            if entry.file_name().to_str() == Some("llvm") {
+                continue;
             }
+            let path = t!(entry.path().canonicalize());
+            rm_rf(&path);
         }
     }
 }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 7a4abcd1dc0..983442270d2 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -820,7 +820,7 @@ impl Step for Rustc {
 
         let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
             if compiler.stage == 1 {
-                cargo.rustflag(&format!("-Cprofile-generate={}", path));
+                cargo.rustflag(&format!("-Cprofile-generate={path}"));
                 // Apparently necessary to avoid overflowing the counters during
                 // a Cargo build profile
                 cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");
@@ -830,7 +830,7 @@ impl Step for Rustc {
             }
         } else if let Some(path) = &builder.config.rust_profile_use {
             if compiler.stage == 1 {
-                cargo.rustflag(&format!("-Cprofile-use={}", path));
+                cargo.rustflag(&format!("-Cprofile-use={path}"));
                 cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
                 true
             } else {
@@ -863,7 +863,7 @@ impl Step for Rustc {
                         RustcLto::Fat => "fat",
                         _ => unreachable!(),
                     };
-                    cargo.rustflag(&format!("-Clto={}", lto_type));
+                    cargo.rustflag(&format!("-Clto={lto_type}"));
                     cargo.rustflag("-Cembed-bitcode=yes");
                 }
                 RustcLto::ThinLocal => { /* Do nothing, this is the default */ }
@@ -1197,7 +1197,7 @@ impl Step for CodegenBackend {
         let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build");
         cargo
             .arg("--manifest-path")
-            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
+            .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
         rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
 
         let tmp_stamp = out_dir.join(".tmp.stamp");
@@ -1302,7 +1302,7 @@ fn codegen_backend_stamp(
 ) -> PathBuf {
     builder
         .cargo_out(compiler, Mode::Codegen, target)
-        .join(format!(".librustc_codegen_{}.stamp", backend))
+        .join(format!(".librustc_codegen_{backend}.stamp"))
 }
 
 pub fn compiler_file(
@@ -1317,7 +1317,7 @@ pub fn compiler_file(
     }
     let mut cmd = Command::new(compiler);
     cmd.args(builder.cflags(target, GitRepo::Rustc, c));
-    cmd.arg(format!("-print-file-name={}", file));
+    cmd.arg(format!("-print-file-name={file}"));
     let out = output(&mut cmd);
     PathBuf::from(out.trim())
 }
@@ -1841,10 +1841,10 @@ pub fn run_cargo(
         });
         let path_to_add = match max {
             Some(triple) => triple.0.to_str().unwrap(),
-            None => panic!("no output generated for {:?} {:?}", prefix, extension),
+            None => panic!("no output generated for {prefix:?} {extension:?}"),
         };
         if is_dylib(path_to_add) {
-            let candidate = format!("{}.lib", path_to_add);
+            let candidate = format!("{path_to_add}.lib");
             let candidate = PathBuf::from(candidate);
             if candidate.exists() {
                 deps.push((candidate, DependencyType::Target));
@@ -1896,10 +1896,10 @@ pub fn stream_cargo(
         cargo.arg(arg);
     }
 
-    builder.verbose(&format!("running: {:?}", cargo));
+    builder.verbose(&format!("running: {cargo:?}"));
     let mut child = match cargo.spawn() {
         Ok(child) => child,
-        Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
+        Err(e) => panic!("failed to execute command: {cargo:?}\nerror: {e}"),
     };
 
     // Spawn Cargo slurping up its JSON output. We'll start building up the
@@ -1912,12 +1912,12 @@ pub fn stream_cargo(
             Ok(msg) => {
                 if builder.config.json_output {
                     // Forward JSON to stdout.
-                    println!("{}", line);
+                    println!("{line}");
                 }
                 cb(msg)
             }
             // If this was informational, just print it out and continue
-            Err(_) => println!("{}", line),
+            Err(_) => println!("{line}"),
         }
     }
 
@@ -1925,9 +1925,8 @@ pub fn stream_cargo(
     let status = t!(child.wait());
     if builder.is_verbose() && !status.success() {
         eprintln!(
-            "command did not execute successfully: {:?}\n\
-                  expected success, got: {}",
-            cargo, status
+            "command did not execute successfully: {cargo:?}\n\
+                  expected success, got: {status}"
         );
     }
     status.success()
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 856a73a22b5..45bea9608fc 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -232,8 +232,8 @@ pub struct Config {
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
-    pub llvm_bolt_profile_generate: bool,
-    pub llvm_bolt_profile_use: Option<String>,
+
+    pub reproducible_artifacts: Vec<String>,
 
     pub build: TargetSelection,
     pub hosts: Vec<TargetSelection>,
@@ -356,7 +356,7 @@ impl FromStr for LlvmLibunwind {
             "no" => Ok(Self::No),
             "in-tree" => Ok(Self::InTree),
             "system" => Ok(Self::System),
-            invalid => Err(format!("Invalid value '{}' for rust.llvm-libunwind config.", invalid)),
+            invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")),
         }
     }
 }
@@ -420,7 +420,7 @@ impl std::str::FromStr for RustcLto {
             "thin" => Ok(RustcLto::Thin),
             "fat" => Ok(RustcLto::Fat),
             "off" => Ok(RustcLto::Off),
-            _ => Err(format!("Invalid value for rustc LTO: {}", s)),
+            _ => Err(format!("Invalid value for rustc LTO: {s}")),
         }
     }
 }
@@ -498,7 +498,7 @@ impl fmt::Display for TargetSelection {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.triple)?;
         if let Some(file) = self.file {
-            write!(f, "({})", file)?;
+            write!(f, "({file})")?;
         }
         Ok(())
     }
@@ -506,7 +506,7 @@ impl fmt::Display for TargetSelection {
 
 impl fmt::Debug for TargetSelection {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self)
+        write!(f, "{self}")
     }
 }
 
@@ -938,8 +938,7 @@ impl<'de> serde::de::Visitor<'de> for OptimizeVisitor {
 
 fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
     format!(
-        r#"unrecognized option for rust optimize: "{}", expected one of 0, 1, 2, 3, "s", "z", true, false"#,
-        v
+        r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"#
     )
 }
 
@@ -1128,15 +1127,6 @@ impl Config {
         config.free_args = std::mem::take(&mut flags.free_args);
         config.llvm_profile_use = flags.llvm_profile_use;
         config.llvm_profile_generate = flags.llvm_profile_generate;
-        config.llvm_bolt_profile_generate = flags.llvm_bolt_profile_generate;
-        config.llvm_bolt_profile_use = flags.llvm_bolt_profile_use;
-
-        if config.llvm_bolt_profile_generate && config.llvm_bolt_profile_use.is_some() {
-            eprintln!(
-                "Cannot use both `llvm_bolt_profile_generate` and `llvm_bolt_profile_use` at the same time"
-            );
-            exit!(1);
-        }
 
         // Infer the rest of the configuration.
 
@@ -1226,7 +1216,7 @@ impl Config {
             include_path.push("src");
             include_path.push("bootstrap");
             include_path.push("defaults");
-            include_path.push(format!("config.{}.toml", include));
+            include_path.push(format!("config.{include}.toml"));
             let included_toml = get_toml(&include_path);
             toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate);
         }
@@ -1472,6 +1462,8 @@ impl Config {
             config.rust_profile_generate = flags.rust_profile_generate;
         }
 
+        config.reproducible_artifacts = flags.reproducible_artifact;
+
         // rust_info must be set before is_ci_llvm_available() is called.
         let default = config.channel == "dev";
         config.omit_git_hash = omit_git_hash.unwrap_or(default);
@@ -1516,7 +1508,7 @@ impl Config {
             let asserts = llvm_assertions.unwrap_or(false);
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
-                    assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
+                    assert!(s == "if-available", "unknown option `{s}` for download-ci-llvm");
                     crate::llvm::is_ci_llvm_available(&config, asserts)
                 }
                 Some(StringOrBool::Bool(b)) => b,
@@ -1750,7 +1742,7 @@ impl Config {
         if self.dry_run() {
             return Ok(());
         }
-        self.verbose(&format!("running: {:?}", cmd));
+        self.verbose(&format!("running: {cmd:?}"));
         build_helper::util::try_run(cmd, self.is_verbose())
     }
 
@@ -1790,10 +1782,10 @@ impl Config {
     pub(crate) fn artifact_version_part(&self, commit: &str) -> String {
         let (channel, version) = if self.rust_info.is_managed_git_subrepository() {
             let mut channel = self.git();
-            channel.arg("show").arg(format!("{}:src/ci/channel", commit));
+            channel.arg("show").arg(format!("{commit}:src/ci/channel"));
             let channel = output(&mut channel);
             let mut version = self.git();
-            version.arg("show").arg(format!("{}:src/version", commit));
+            version.arg("show").arg(format!("{commit}:src/version"));
             let version = output(&mut version);
             (channel.trim().to_owned(), version.trim().to_owned())
         } else {
@@ -1810,10 +1802,10 @@ impl Config {
                         "help: consider using a git checkout or ensure these files are readable"
                     );
                     if let Err(channel) = channel {
-                        eprintln!("reading {}/src/ci/channel failed: {:?}", src, channel);
+                        eprintln!("reading {src}/src/ci/channel failed: {channel:?}");
                     }
                     if let Err(version) = version {
-                        eprintln!("reading {}/src/version failed: {:?}", src, version);
+                        eprintln!("reading {src}/src/version failed: {version:?}");
                     }
                     panic!();
                 }
@@ -1939,7 +1931,7 @@ impl Config {
 
     pub fn verbose(&self, msg: &str) {
         if self.verbose > 0 {
-            println!("{}", msg);
+            println!("{msg}");
         }
     }
 
@@ -2016,8 +2008,7 @@ impl Config {
         {
             let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
             eprintln!(
-                "Unexpected rustc version: {}, we should use {}/{} to build source with {}",
-                rustc_version, prev_version, source_version, source_version
+                "Unexpected rustc version: {rustc_version}, we should use {prev_version}/{source_version} to build source with {source_version}"
             );
             exit!(1);
         }
@@ -2031,7 +2022,7 @@ impl Config {
             Some(StringOrBool::Bool(true)) => false,
             Some(StringOrBool::String(s)) if s == "if-unchanged" => true,
             Some(StringOrBool::String(other)) => {
-                panic!("unrecognized option for download-rustc: {}", other)
+                panic!("unrecognized option for download-rustc: {other}")
             }
         };
 
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index c8750c19388..32da4ac29a4 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -18,9 +18,7 @@ use std::process::Command;
 
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
-use sha2::Digest;
 
-use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::channel;
@@ -162,7 +160,7 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
         if let Some(file_path) = file_path {
             found.push(file_path);
         } else {
-            panic!("Could not find '{}' in {:?}", file, path);
+            panic!("Could not find '{file}' in {path:?}");
         }
     }
 
@@ -1480,8 +1478,8 @@ impl Step for Extended {
         rtf.push('}');
 
         fn filter(contents: &str, marker: &str) -> String {
-            let start = format!("tool-{}-start", marker);
-            let end = format!("tool-{}-end", marker);
+            let start = format!("tool-{marker}-start");
+            let end = format!("tool-{marker}-end");
             let mut lines = Vec::new();
             let mut omitted = false;
             for line in contents.lines() {
@@ -1862,7 +1860,7 @@ impl Step for Extended {
             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
 
-            builder.info(&format!("building `msi` installer with {:?}", light));
+            builder.info(&format!("building `msi` installer with {light:?}"));
             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
             let mut cmd = Command::new(&light);
             cmd.arg("-nologo")
@@ -1941,19 +1939,7 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
         return;
     }
 
-    // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
-    // This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
-    // We perform the instrumentation/optimization here, on the fly, just before they are being
-    // packaged into some destination directory.
-    let postprocessed = if builder.config.llvm_bolt_profile_generate {
-        builder.ensure(BoltInstrument::new(source.to_path_buf()))
-    } else if let Some(path) = &builder.config.llvm_bolt_profile_use {
-        builder.ensure(BoltOptimize::new(source.to_path_buf(), path.into()))
-    } else {
-        source.to_path_buf()
-    };
-
-    builder.install(&postprocessed, destination, 0o644);
+    builder.install(&source, destination, 0o644);
 }
 
 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
@@ -1996,7 +1982,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
     {
         let mut cmd = Command::new(llvm_config);
         cmd.arg("--libfiles");
-        builder.verbose(&format!("running {:?}", cmd));
+        builder.verbose(&format!("running {cmd:?}"));
         let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
@@ -2038,117 +2024,6 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
     }
 }
 
-/// Creates an output path to a BOLT-manipulated artifact for the given `file`.
-/// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
-/// files with the same name.
-///
-/// We need to keep the file-name the same though, to make sure that copying the manipulated file
-/// to a directory will not change the final file path.
-fn create_bolt_output_path(builder: &Builder<'_>, file: &Path, hash: &str) -> PathBuf {
-    let directory = builder.out.join("bolt").join(hash);
-    t!(fs::create_dir_all(&directory));
-    directory.join(file.file_name().unwrap())
-}
-
-/// Instrument the provided file with BOLT.
-/// Returns a path to the instrumented artifact.
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
-pub struct BoltInstrument {
-    file: PathBuf,
-    hash: String,
-}
-
-impl BoltInstrument {
-    fn new(file: PathBuf) -> Self {
-        let mut hasher = sha2::Sha256::new();
-        hasher.update(t!(fs::read(&file)));
-        let hash = hex::encode(hasher.finalize().as_slice());
-
-        Self { file, hash }
-    }
-}
-
-impl Step for BoltInstrument {
-    type Output = PathBuf;
-
-    const ONLY_HOSTS: bool = false;
-    const DEFAULT: bool = false;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
-    }
-
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
-        if builder.build.config.dry_run() {
-            return self.file.clone();
-        }
-
-        if builder.build.config.llvm_from_ci {
-            println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
-        }
-
-        println!("Instrumenting {} with BOLT", self.file.display());
-
-        let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
-        if !output_path.is_file() {
-            instrument_with_bolt(&self.file, &output_path);
-        }
-        output_path
-    }
-}
-
-/// Optimize the provided file with BOLT.
-/// Returns a path to the optimized artifact.
-///
-/// The hash is stored in the step to make sure that we don't optimize the same file
-/// twice (even under  different file paths).
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
-pub struct BoltOptimize {
-    file: PathBuf,
-    profile: PathBuf,
-    hash: String,
-}
-
-impl BoltOptimize {
-    fn new(file: PathBuf, profile: PathBuf) -> Self {
-        let mut hasher = sha2::Sha256::new();
-        hasher.update(t!(fs::read(&file)));
-        hasher.update(t!(fs::read(&profile)));
-        let hash = hex::encode(hasher.finalize().as_slice());
-
-        Self { file, profile, hash }
-    }
-}
-
-impl Step for BoltOptimize {
-    type Output = PathBuf;
-
-    const ONLY_HOSTS: bool = false;
-    const DEFAULT: bool = false;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
-    }
-
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
-        if builder.build.config.dry_run() {
-            return self.file.clone();
-        }
-
-        if builder.build.config.llvm_from_ci {
-            println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
-        }
-
-        println!("Optimizing {} with BOLT", self.file.display());
-
-        let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
-        if !output_path.is_file() {
-            optimize_with_bolt(&self.file, &self.profile, &output_path);
-        }
-        output_path
-    }
-}
-
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct LlvmTools {
     pub target: TargetSelection,
@@ -2175,7 +2050,7 @@ impl Step for LlvmTools {
         /* run only if llvm-config isn't used */
         if let Some(config) = builder.config.target_config.get(&target) {
             if let Some(ref _s) = config.llvm_config {
-                builder.info(&format!("Skipping LlvmTools ({}): external LLVM", target));
+                builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
                 return None;
             }
         }
@@ -2231,7 +2106,7 @@ impl Step for RustDev {
         /* run only if llvm-config isn't used */
         if let Some(config) = builder.config.target_config.get(&target) {
             if let Some(ref _s) = config.llvm_config {
-                builder.info(&format!("Skipping RustDev ({}): external LLVM", target));
+                builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
                 return None;
             }
         }
@@ -2390,8 +2265,8 @@ impl Step for ReproducibleArtifacts {
             tarball.add_file(path, ".", 0o644);
             added_anything = true;
         }
-        if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() {
-            tarball.add_file(path, ".", 0o644);
+        for profile in &builder.config.reproducible_artifacts {
+            tarball.add_file(profile, ".", 0o644);
             added_anything = true;
         }
         if added_anything { Some(tarball.generate()) } else { None }
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 2ccbf179cca..9cb3546ba0a 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -147,7 +147,7 @@ impl<P: Step> Step for RustbookSrc<P> {
 
         if !builder.config.dry_run() && !(up_to_date(&src, &index) || up_to_date(&rustbook, &index))
         {
-            builder.info(&format!("Rustbook ({}) - {}", target, name));
+            builder.info(&format!("Rustbook ({target}) - {name}"));
             let _ = fs::remove_dir_all(&out);
 
             builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(out));
@@ -219,7 +219,7 @@ impl Step for TheBook {
         for edition in &["first-edition", "second-edition", "2018-edition"] {
             builder.ensure(RustbookSrc {
                 target,
-                name: INTERNER.intern_string(format!("book/{}", edition)),
+                name: INTERNER.intern_string(format!("book/{edition}")),
                 src: INTERNER.intern_path(absolute_path.join(edition)),
                 // There should only be one book that is marked as the parent for each target, so
                 // treat the other editions as not having a parent.
@@ -966,7 +966,7 @@ impl Step for UnstableBookGen {
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
 
-        builder.info(&format!("Generating unstable book md files ({})", target));
+        builder.info(&format!("Generating unstable book md files ({target})"));
         let out = builder.md_doc_out(target).join("unstable-book");
         builder.create_dir(&out);
         builder.remove_dir(&out);
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index 1316461fde0..a4135b06e9d 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -64,7 +64,7 @@ impl Config {
         if self.dry_run() {
             return true;
         }
-        self.verbose(&format!("running: {:?}", cmd));
+        self.verbose(&format!("running: {cmd:?}"));
         check_run(cmd, self.is_verbose())
     }
 
@@ -206,7 +206,7 @@ impl Config {
     }
 
     fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
-        println!("downloading {}", url);
+        println!("downloading {url}");
         // Try curl. If that fails and we are on windows, fallback to PowerShell.
         let mut curl = Command::new("curl");
         curl.args(&[
@@ -248,7 +248,7 @@ impl Config {
                 }
             }
             if !help_on_error.is_empty() {
-                eprintln!("{}", help_on_error);
+                eprintln!("{help_on_error}");
             }
             crate::exit!(1);
         }
@@ -646,7 +646,7 @@ download-rustc = false
     fn download_ci_llvm(&self, llvm_sha: &str) {
         let llvm_assertions = self.llvm_assertions;
 
-        let cache_prefix = format!("llvm-{}-{}", llvm_sha, llvm_assertions);
+        let cache_prefix = format!("llvm-{llvm_sha}-{llvm_assertions}");
         let cache_dst = self.out.join("cache");
         let rustc_cache = cache_dst.join(cache_prefix);
         if !rustc_cache.exists() {
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index d67aafff841..a1e0a440729 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -149,12 +149,9 @@ pub struct Flags {
     /// generate PGO profile with llvm built for rustc
     #[arg(global(true), long)]
     pub llvm_profile_generate: bool,
-    /// generate BOLT profile for LLVM build
+    /// Additional reproducible artifacts that should be added to the reproducible artifacts archive.
     #[arg(global(true), long)]
-    pub llvm_bolt_profile_generate: bool,
-    /// use BOLT profile for LLVM build
-    #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
-    pub llvm_bolt_profile_use: Option<String>,
+    pub reproducible_artifact: Vec<String>,
     #[arg(global(true))]
     /// paths for the subcommand
     pub paths: Vec<PathBuf>,
@@ -189,7 +186,7 @@ impl Flags {
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
             if let Some(s) = paths {
-                println!("{}", s);
+                println!("{s}");
             } else {
                 panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
@@ -366,7 +363,11 @@ pub enum Subcommand {
     /// Clean out build directories
     Clean {
         #[arg(long)]
+        /// Clean the entire build directory (not used by default)
         all: bool,
+        #[arg(long, value_name = "N")]
+        /// Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used.
+        stage: Option<u32>,
     },
     /// Build distribution artifacts
     Dist,
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index cfc9c4de60f..3f9230aa5d5 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -22,7 +22,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
         cmd.arg("--check");
     }
     cmd.args(paths);
-    let cmd_debug = format!("{:?}", cmd);
+    let cmd_debug = format!("{cmd:?}");
     let mut cmd = cmd.spawn().expect("running rustfmt");
     // poor man's async: return a closure that'll wait for rustfmt's completion
     move |block: bool| -> bool {
@@ -115,7 +115,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
     let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
     for ignore in rustfmt_config.ignore {
-        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
+        ignore_fmt.add(&format!("!{ignore}")).expect(&ignore);
     }
     let git_available = match Command::new("git")
         .arg("--version")
@@ -153,13 +153,13 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                     entry.split(' ').nth(1).expect("every git status entry should list a path")
                 });
             for untracked_path in untracked_paths {
-                println!("skip untracked path {} during rustfmt invocations", untracked_path);
+                println!("skip untracked path {untracked_path} during rustfmt invocations");
                 // The leading `/` makes it an exact match against the
                 // repository root, rather than a glob. Without that, if you
                 // have `foo.rs` in the repository root it will also match
                 // against anything like `compiler/rustc_foo/src/foo.rs`,
                 // preventing the latter from being formatted.
-                ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
+                ignore_fmt.add(&format!("!/{untracked_path}")).expect(&untracked_path);
             }
             // Only check modified files locally to speed up runtime.
             // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through;
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 365deb8e155..8c674d075b8 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -39,7 +39,6 @@ use crate::util::{
     dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
 };
 
-mod bolt;
 mod builder;
 mod cache;
 mod cc_detect;
@@ -484,7 +483,7 @@ impl Build {
             .unwrap()
             .trim();
         if local_release.split('.').take(2).eq(version.split('.').take(2)) {
-            build.verbose(&format!("auto-detected local-rebuild {}", local_release));
+            build.verbose(&format!("auto-detected local-rebuild {local_release}"));
             build.local_rebuild = true;
         }
 
@@ -713,7 +712,7 @@ impl Build {
         if failures.len() > 0 {
             eprintln!("\n{} command(s) did not execute successfully:\n", failures.len());
             for failure in failures.iter() {
-                eprintln!("  - {}\n", failure);
+                eprintln!("  - {failure}\n");
             }
             exit!(1);
         }
@@ -959,7 +958,7 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
-        self.verbose(&format!("running: {:?}", cmd));
+        self.verbose(&format!("running: {cmd:?}"));
         run(cmd, self.is_verbose())
     }
 
@@ -968,7 +967,7 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
-        self.verbose(&format!("running: {:?}", cmd));
+        self.verbose(&format!("running: {cmd:?}"));
         run_suppressed(cmd)
     }
 
@@ -980,10 +979,10 @@ impl Build {
             return true;
         }
         if !self.fail_fast {
-            self.verbose(&format!("running: {:?}", cmd));
+            self.verbose(&format!("running: {cmd:?}"));
             if !try_run_suppressed(cmd) {
                 let mut failures = self.delayed_failures.borrow_mut();
-                failures.push(format!("{:?}", cmd));
+                failures.push(format!("{cmd:?}"));
                 return false;
             }
         } else {
@@ -998,7 +997,7 @@ impl Build {
             #[allow(deprecated)] // can't use Build::try_run, that's us
             if self.config.try_run(cmd).is_err() {
                 let mut failures = self.delayed_failures.borrow_mut();
-                failures.push(format!("{:?}", cmd));
+                failures.push(format!("{cmd:?}"));
                 return false;
             }
         } else {
@@ -1014,7 +1013,7 @@ impl Build {
     /// Prints a message if this build is configured in more verbose mode than `level`.
     fn verbose_than(&self, level: usize, msg: &str) {
         if self.is_verbose_than(level) {
-            println!("{}", msg);
+            println!("{msg}");
         }
     }
 
@@ -1022,7 +1021,7 @@ impl Build {
         match self.config.dry_run {
             DryRun::SelfCheck => return,
             DryRun::Disabled | DryRun::UserSelected => {
-                println!("{}", msg);
+                println!("{msg}");
             }
         }
     }
@@ -1147,7 +1146,7 @@ impl Build {
         match which {
             GitRepo::Rustc => {
                 let sha = self.rust_sha().unwrap_or(&self.version);
-                Some(format!("/rustc/{}", sha))
+                Some(format!("/rustc/{sha}"))
             }
             GitRepo::Llvm => Some(String::from("/rustc/llvm")),
         }
@@ -1200,10 +1199,10 @@ impl Build {
             let map = format!("{}={}", self.src.display(), map_to);
             let cc = self.cc(target);
             if cc.ends_with("clang") || cc.ends_with("gcc") {
-                base.push(format!("-fdebug-prefix-map={}", map));
+                base.push(format!("-fdebug-prefix-map={map}"));
             } else if cc.ends_with("clang-cl.exe") {
                 base.push("-Xclang".into());
-                base.push(format!("-fdebug-prefix-map={}", map));
+                base.push(format!("-fdebug-prefix-map={map}"));
             }
         }
         base
@@ -1232,9 +1231,7 @@ impl Build {
         }
         match self.cxx.borrow().get(&target) {
             Some(p) => Ok(p.path().into()),
-            None => {
-                Err(format!("target `{}` is not configured as a host, only as a target", target))
-            }
+            None => Err(format!("target `{target}` is not configured as a host, only as a target")),
         }
     }
 
@@ -1277,7 +1274,7 @@ impl Build {
             }
 
             let no_threads = util::lld_flag_no_threads(target.contains("windows"));
-            options[1] = Some(format!("-Clink-arg=-Wl,{}", no_threads));
+            options[1] = Some(format!("-Clink-arg=-Wl,{no_threads}"));
         }
 
         IntoIterator::into_iter(options).flatten()
@@ -1404,11 +1401,11 @@ impl Build {
                 if !self.config.omit_git_hash {
                     format!("{}-beta.{}", num, self.beta_prerelease_version())
                 } else {
-                    format!("{}-beta", num)
+                    format!("{num}-beta")
                 }
             }
-            "nightly" => format!("{}-nightly", num),
-            _ => format!("{}-dev", num),
+            "nightly" => format!("{num}-nightly"),
+            _ => format!("{num}-dev"),
         }
     }
 
@@ -1456,7 +1453,7 @@ impl Build {
             "stable" => num.to_string(),
             "beta" => "beta".to_string(),
             "nightly" => "nightly".to_string(),
-            _ => format!("{}-dev", num),
+            _ => format!("{num}-dev"),
         }
     }
 
@@ -1487,7 +1484,7 @@ impl Build {
 
     /// Returns the `a.b.c` version that the given package is at.
     fn release_num(&self, package: &str) -> String {
-        let toml_file_name = self.src.join(&format!("src/tools/{}/Cargo.toml", package));
+        let toml_file_name = self.src.join(&format!("src/tools/{package}/Cargo.toml"));
         let toml = t!(fs::read_to_string(&toml_file_name));
         for line in toml.lines() {
             if let Some(stripped) =
@@ -1497,7 +1494,7 @@ impl Build {
             }
         }
 
-        panic!("failed to find version in {}'s Cargo.toml", package)
+        panic!("failed to find version in {package}'s Cargo.toml")
     }
 
     /// Returns `true` if unstable features should be enabled for the compiler
@@ -1589,7 +1586,7 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
-        self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst));
+        self.verbose_than(1, &format!("Copy {src:?} to {dst:?}"));
         if src == dst {
             return;
         }
@@ -1680,7 +1677,7 @@ impl Build {
             return;
         }
         let dst = dstdir.join(src.file_name().unwrap());
-        self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst));
+        self.verbose_than(1, &format!("Install {src:?} to {dst:?}"));
         t!(fs::create_dir_all(dstdir));
         if !src.exists() {
             panic!("Error: File \"{}\" not found!", src.display());
@@ -1714,7 +1711,7 @@ impl Build {
         let iter = match fs::read_dir(dir) {
             Ok(v) => v,
             Err(_) if self.config.dry_run() => return vec![].into_iter(),
-            Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
+            Err(err) => panic!("could not read dir {dir:?}: {err:?}"),
         };
         iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
     }
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 02fef4b3e83..d8718d26848 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -24,6 +24,7 @@ use crate::util::{self, exe, output, t, up_to_date};
 use crate::{CLang, GitRepo, Kind};
 
 use build_helper::ci::CiEnv;
+use build_helper::git::get_git_merge_base;
 
 #[derive(Clone)]
 pub struct LlvmResult {
@@ -128,13 +129,19 @@ pub fn prebuilt_llvm_config(
 /// This retrieves the LLVM sha we *want* to use, according to git history.
 pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
     let llvm_sha = if is_git {
+        // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
+        // walk back further to the last bors merge commit that actually changed LLVM. The first
+        // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
+        // in that case.
+        let closest_upstream =
+            get_git_merge_base(Some(&config.src)).unwrap_or_else(|_| "HEAD".into());
         let mut rev_list = config.git();
         rev_list.args(&[
             PathBuf::from("rev-list"),
             format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
             "-n1".into(),
             "--first-parent".into(),
-            "HEAD".into(),
+            closest_upstream.into(),
             "--".into(),
             config.src.join("src/llvm-project"),
             config.src.join("src/bootstrap/download-ci-llvm-stamp"),
@@ -342,12 +349,6 @@ impl Step for Llvm {
         if let Some(path) = builder.config.llvm_profile_use.as_ref() {
             cfg.define("LLVM_PROFDATA_FILE", &path);
         }
-        if builder.config.llvm_bolt_profile_generate
-            || builder.config.llvm_bolt_profile_use.is_some()
-        {
-            // Relocations are required for BOLT to work.
-            ldflags.push_all("-Wl,-q");
-        }
 
         // Disable zstd to avoid a dependency on libzstd.so.
         cfg.define("LLVM_ENABLE_ZSTD", "OFF");
@@ -500,8 +501,8 @@ impl Step for Llvm {
             let version = output(cmd.arg("--version"));
             let major = version.split('.').next().unwrap();
             let lib_name = match llvm_version_suffix {
-                Some(s) => format!("libLLVM-{}{}.dylib", major, s),
-                None => format!("libLLVM-{}.dylib", major),
+                Some(s) => format!("libLLVM-{major}{s}.dylib"),
+                None => format!("libLLVM-{major}.dylib"),
             };
 
             let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
@@ -525,11 +526,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = output(cmd.arg("--version"));
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 14 {
+        if major >= 15 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {}, need >=14.0\n\n", version)
+    panic!("\n\nbad LLVM version: {version}, need >=15.0\n\n")
 }
 
 fn configure_cmake(
@@ -686,10 +687,10 @@ fn configure_cmake(
         }
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cflags.push(&format!(" --target={}", target));
+        cflags.push(&format!(" --target={target}"));
     }
     for flag in extra_compiler_flags {
-        cflags.push(&format!(" {}", flag));
+        cflags.push(&format!(" {flag}"));
     }
     cfg.define("CMAKE_C_FLAGS", cflags);
     let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm, CLang::Cxx).join(" ").into();
@@ -698,10 +699,10 @@ fn configure_cmake(
         cxxflags.push(s);
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cxxflags.push(&format!(" --target={}", target));
+        cxxflags.push(&format!(" --target={target}"));
     }
     for flag in extra_compiler_flags {
-        cxxflags.push(&format!(" {}", flag));
+        cxxflags.push(&format!(" {flag}"));
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
@@ -772,7 +773,7 @@ fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmak
 fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
     let kind = if host == target { "HOST" } else { "TARGET" };
     let target_u = target.replace("-", "_");
-    env::var_os(&format!("{}_{}", var_base, target))
+    env::var_os(&format!("{var_base}_{target}"))
         .or_else(|| env::var_os(&format!("{}_{}", var_base, target_u)))
         .or_else(|| env::var_os(&format!("{}_{}", kind, var_base)))
         .or_else(|| env::var_os(var_base))
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 145ae6f44da..7e83b508e94 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -188,7 +188,7 @@ than building it.
         // Externally configured LLVM requires FileCheck to exist
         let filecheck = build.llvm_filecheck(build.build);
         if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
-            panic!("FileCheck executable {:?} does not exist", filecheck);
+            panic!("FileCheck executable {filecheck:?} does not exist");
         }
     }
 
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 2075c58598d..30730f50491 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -32,6 +32,7 @@ static SETTINGS_HASHES: &[&str] = &[
     "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
     "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
     "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
 ];
 static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
 
@@ -92,7 +93,7 @@ impl FromStr for Profile {
                 Ok(Profile::Tools)
             }
             "none" => Ok(Profile::None),
-            _ => Err(format!("unknown profile: '{}'", s)),
+            _ => Err(format!("unknown profile: '{s}'")),
         }
     }
 }
@@ -167,7 +168,7 @@ pub fn setup(config: &Config, profile: Profile) {
 
     println!("To get started, try one of the following commands:");
     for cmd in suggestions {
-        println!("- `x.py {}`", cmd);
+        println!("- `x.py {cmd}`");
     }
 
     if profile != Profile::Dist {
@@ -208,9 +209,8 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
 
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
-    profile = \"{}\"\n\
-    changelog-seen = {}\n",
-        profile, VERSION
+    profile = \"{profile}\"\n\
+    changelog-seen = {VERSION}\n"
     );
 
     t!(fs::write(path, settings));
@@ -341,7 +341,7 @@ fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool {
         return false;
     };
 
-    let pathbuf = pathbuf.join(format!("rustc{}", EXE_SUFFIX));
+    let pathbuf = pathbuf.join(format!("rustc{EXE_SUFFIX}"));
 
     if pathbuf.exists() {
         return true;
@@ -394,7 +394,7 @@ pub fn interactive_path() -> io::Result<Profile> {
         break match parse_with_abbrev(&input) {
             Ok(profile) => profile,
             Err(err) => {
-                eprintln!("error: {}", err);
+                eprintln!("error: {err}");
                 eprintln!("note: press Ctrl+C to exit");
                 continue;
             }
diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs
index 7fa8a4d9d7f..95d909c5730 100644
--- a/src/bootstrap/tarball.rs
+++ b/src/bootstrap/tarball.rs
@@ -309,7 +309,7 @@ impl<'a> Tarball<'a> {
         let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller);
 
         let package_name = self.package_name();
-        self.builder.info(&format!("Dist {}", package_name));
+        self.builder.info(&format!("Dist {package_name}"));
         let _time = crate::util::timeit(self.builder);
 
         build_cli(&self, &mut cmd);
@@ -344,7 +344,7 @@ impl<'a> Tarball<'a> {
             .unwrap_or("gz");
 
         GeneratedTarball {
-            path: crate::dist::distdir(self.builder).join(format!("{}.tar.{}", package_name, ext)),
+            path: crate::dist::distdir(self.builder).join(format!("{package_name}.tar.{ext}")),
             decompressed_output,
             work: self.temp_dir,
         }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 820fe5e5294..4bfb16928f1 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -126,7 +126,7 @@ You can skip linkcheck with --exclude src/tools/linkchecker"
             );
         }
 
-        builder.info(&format!("Linkcheck ({})", host));
+        builder.info(&format!("Linkcheck ({host})"));
 
         // Test the linkchecker itself.
         let bootstrap_host = builder.config.build;
@@ -557,7 +557,7 @@ impl Miri {
         if builder.config.dry_run() {
             String::new()
         } else {
-            builder.verbose(&format!("running: {:?}", cargo));
+            builder.verbose(&format!("running: {cargo:?}"));
             let out =
                 cargo.output().expect("We already ran `cargo miri setup` before and that worked");
             assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
@@ -565,7 +565,7 @@ impl Miri {
             let stdout = String::from_utf8(out.stdout)
                 .expect("`cargo miri setup` stdout is not valid UTF-8");
             let sysroot = stdout.trim_end();
-            builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
+            builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
             sysroot.to_owned()
         }
     }
@@ -2580,7 +2580,7 @@ impl Step for RemoteCopyLibs {
 
         builder.ensure(compile::Std::new(compiler, target));
 
-        builder.info(&format!("REMOTE copy libs to emulator ({})", target));
+        builder.info(&format!("REMOTE copy libs to emulator ({target})"));
 
         let server = builder.ensure(tool::RemoteTestServer { compiler, target });
 
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index eb65c8bee09..308023537d5 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -83,13 +83,13 @@ static NIGHTLY_TOOLS: &[(&str, &str)] = &[
 
 fn print_error(tool: &str, submodule: &str) {
     eprintln!();
-    eprintln!("We detected that this PR updated '{}', but its tests failed.", tool);
+    eprintln!("We detected that this PR updated '{tool}', but its tests failed.");
     eprintln!();
-    eprintln!("If you do intend to update '{}', please check the error messages above and", tool);
+    eprintln!("If you do intend to update '{tool}', please check the error messages above and");
     eprintln!("commit another update.");
     eprintln!();
-    eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
-    eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
+    eprintln!("If you do NOT intend to update '{tool}', please ensure you did not accidentally");
+    eprintln!("change the submodule at '{submodule}'. You may ask your reviewer for the");
     eprintln!("proper steps.");
     crate::exit!(3);
 }
@@ -105,7 +105,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
     let output = match output {
         Ok(o) => o,
         Err(e) => {
-            eprintln!("Failed to get changed files: {:?}", e);
+            eprintln!("Failed to get changed files: {e:?}");
             crate::exit!(1);
         }
     };
@@ -114,12 +114,12 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
 
     for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
         let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule));
-        eprintln!("Verifying status of {}...", tool);
+        eprintln!("Verifying status of {tool}...");
         if !changed {
             continue;
         }
 
-        eprintln!("This PR updated '{}', verifying if status is 'test-pass'...", submodule);
+        eprintln!("This PR updated '{submodule}', verifying if status is 'test-pass'...");
         if toolstates[*tool] != ToolState::TestPass {
             print_error(tool, submodule);
         }
@@ -172,7 +172,7 @@ impl Step for ToolStateCheck {
         for (tool, _) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
             if !toolstates.contains_key(*tool) {
                 did_error = true;
-                eprintln!("error: Tool `{}` was not recorded in tool state.", tool);
+                eprintln!("error: Tool `{tool}` was not recorded in tool state.");
             }
         }
 
@@ -190,7 +190,7 @@ impl Step for ToolStateCheck {
             if state != ToolState::TestPass {
                 if !is_nightly {
                     did_error = true;
-                    eprintln!("error: Tool `{}` should be test-pass but is {}", tool, state);
+                    eprintln!("error: Tool `{tool}` should be test-pass but is {state}");
                 } else if in_beta_week {
                     let old_state = old_toolstate
                         .iter()
@@ -200,17 +200,15 @@ impl Step for ToolStateCheck {
                     if state < old_state {
                         did_error = true;
                         eprintln!(
-                            "error: Tool `{}` has regressed from {} to {} during beta week.",
-                            tool, old_state, state
+                            "error: Tool `{tool}` has regressed from {old_state} to {state} during beta week."
                         );
                     } else {
                         // This warning only appears in the logs, which most
                         // people won't read. It's mostly here for testing and
                         // debugging.
                         eprintln!(
-                            "warning: Tool `{}` is not test-pass (is `{}`), \
-                            this should be fixed before beta is branched.",
-                            tool, state
+                            "warning: Tool `{tool}` is not test-pass (is `{state}`), \
+                            this should be fixed before beta is branched."
                         );
                     }
                 }
@@ -323,7 +321,7 @@ fn checkout_toolstate_repo() {
         Err(_) => false,
     };
     if !success {
-        panic!("git clone unsuccessful (status: {:?})", status);
+        panic!("git clone unsuccessful (status: {status:?})");
     }
 }
 
@@ -336,7 +334,7 @@ fn prepare_toolstate_config(token: &str) {
             Err(_) => false,
         };
         if !success {
-            panic!("git config key={} value={} failed (status: {:?})", key, value, status);
+            panic!("git config key={key} value={value} failed (status: {status:?})");
         }
     }
 
@@ -346,7 +344,7 @@ fn prepare_toolstate_config(token: &str) {
     git_config("user.name", "Rust Toolstate Update");
     git_config("credential.helper", "store");
 
-    let credential = format!("https://{}:x-oauth-basic@github.com\n", token,);
+    let credential = format!("https://{token}:x-oauth-basic@github.com\n",);
     let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials");
     t!(fs::write(&git_credential_path, credential));
 }
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 84ed2985464..3c4a21434c0 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -46,9 +46,9 @@ pub use t;
 /// executable for a particular target.
 pub fn exe(name: &str, target: TargetSelection) -> String {
     if target.contains("windows") {
-        format!("{}.exe", name)
+        format!("{name}.exe")
     } else if target.contains("uefi") {
-        format!("{}.efi", name)
+        format!("{name}.efi")
     } else {
         name.to_string()
     }
@@ -161,9 +161,8 @@ pub fn forcing_clang_based_tests() -> bool {
             other => {
                 // Let's make sure typos don't go unnoticed
                 panic!(
-                    "Unrecognized option '{}' set in \
-                        RUSTBUILD_FORCE_CLANG_BASED_TESTS",
-                    other
+                    "Unrecognized option '{other}' set in \
+                        RUSTBUILD_FORCE_CLANG_BASED_TESTS"
                 )
             }
         }
@@ -227,15 +226,14 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
     let status = match cmd.status() {
         Ok(status) => status,
         Err(e) => {
-            println!("failed to execute command: {:?}\nerror: {}", cmd, e);
+            println!("failed to execute command: {cmd:?}\nerror: {e}");
             return false;
         }
     };
     if !status.success() && print_cmd_on_fail {
         println!(
-            "\n\ncommand did not execute successfully: {:?}\n\
-             expected success, got: {}\n\n",
-            cmd, status
+            "\n\ncommand did not execute successfully: {cmd:?}\n\
+             expected success, got: {status}\n\n"
         );
     }
     status.success()
@@ -250,7 +248,7 @@ pub fn run_suppressed(cmd: &mut Command) {
 pub fn try_run_suppressed(cmd: &mut Command) -> bool {
     let output = match cmd.output() {
         Ok(status) => status,
-        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
+        Err(e) => fail(&format!("failed to execute command: {cmd:?}\nerror: {e}")),
     };
     if !output.status.success() {
         println!(
@@ -283,7 +281,7 @@ pub fn make(host: &str) -> PathBuf {
 pub fn output(cmd: &mut Command) -> String {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
-        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
+        Err(e) => fail(&format!("failed to execute command: {cmd:?}\nerror: {e}")),
     };
     if !output.status.success() {
         panic!(
@@ -298,7 +296,7 @@ pub fn output(cmd: &mut Command) -> String {
 pub fn output_result(cmd: &mut Command) -> Result<String, String> {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
-        Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)),
+        Err(e) => return Err(format!("failed to run command: {cmd:?}: {e}")),
     };
     if !output.status.success() {
         return Err(format!(
@@ -328,7 +326,7 @@ pub fn up_to_date(src: &Path, dst: &Path) -> bool {
     let threshold = mtime(dst);
     let meta = match fs::metadata(src) {
         Ok(meta) => meta,
-        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
+        Err(e) => panic!("source {src:?} failed to get metadata: {e}"),
     };
     if meta.is_dir() {
         dir_up_to_date(src, threshold)
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
deleted file mode 100644
index 93d18bcf1b1..00000000000
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
+++ /dev/null
@@ -1,54 +0,0 @@
-FROM ubuntu:22.04
-
-ARG DEBIAN_FRONTEND=noninteractive
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  gcc-multilib \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3.11 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  llvm-14-tools \
-  llvm-14-dev \
-  libedit-dev \
-  libssl-dev \
-  pkg-config \
-  zlib1g-dev \
-  xz-utils \
-  nodejs \
-  mingw-w64 \
-  && rm -rf /var/lib/apt/lists/*
-
-# Install powershell (universal package) so we can test x.ps1 on Linux
-RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
-    dpkg -i powershell.deb && \
-    rm -f powershell.deb
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# We are disabling CI LLVM since this builder is intentionally using a host
-# LLVM, rather than the typical src/llvm-project LLVM.
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-# This is not the latest LLVM version, so some components required by tests may
-# be missing.
-ENV IS_NOT_LATEST_LLVM 1
-
-# Using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
-      --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-14 \
-      --enable-llvm-link-shared \
-      --set rust.thin-lto-import-instr-limit=10
-
-COPY host-x86_64/x86_64-gnu-llvm-14/script.sh /tmp/
-
-ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
index 960683b92bd..444e0275d48 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.10
+FROM ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   file \
   curl \
   ca-certificates \
-  python3 \
+  python3.11 \
   git \
   cmake \
   sudo \
@@ -49,20 +49,6 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
-ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
-           # Run the `mir-opt` tests again but this time for a 32-bit target.
-           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
-           # both 32-bit and 64-bit outputs updated by the PR author, before
-           # the PR is approved and tested for merging.
-           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
-           # despite having different output on 32-bit vs 64-bit targets.
-           ../x --stage 2 test tests/mir-opt \
-                             --host='' --target=i686-unknown-linux-gnu && \
-           # Run the UI test suite again, but in `--pass=check` mode
-           #
-           # This is intended to make sure that both `--pass=check` continues to
-           # work.
-           #
-           ../x.ps1 --stage 2 test tests/ui --pass=check \
-                             --host='' --target=i686-unknown-linux-gnu
+COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/
+
+ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
index 0120fd98298..0120fd98298 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
index 7c75d0df590..1e2b802e64e 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
@@ -45,20 +45,6 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
-ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
-           # Run the `mir-opt` tests again but this time for a 32-bit target.
-           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
-           # both 32-bit and 64-bit outputs updated by the PR author, before
-           # the PR is approved and tested for merging.
-           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
-           # despite having different output on 32-bit vs 64-bit targets.
-           ../x --stage 2 test tests/mir-opt \
-                             --host='' --target=i686-unknown-linux-gnu && \
-           # Run the UI test suite again, but in `--pass=check` mode
-           #
-           # This is intended to make sure that both `--pass=check` continues to
-           # work.
-           #
-           ../x.ps1 --stage 2 test tests/ui --pass=check \
-                             --host='' --target=i686-unknown-linux-gnu
+COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/
+
+ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 55fd6cca85a..6efc1980e60 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -323,7 +323,7 @@ jobs:
           - name: mingw-check-tidy
             <<: *job-linux-16c
 
-          - name: x86_64-gnu-llvm-14
+          - name: x86_64-gnu-llvm-15
             <<: *job-linux-16c
 
           - name: x86_64-gnu-tools
@@ -469,11 +469,6 @@ jobs:
               RUST_BACKTRACE: 1
             <<: *job-linux-8c
 
-          - name: x86_64-gnu-llvm-14
-            env:
-              RUST_BACKTRACE: 1
-            <<: *job-linux-8c
-
           - name: x86_64-gnu-nopt
             <<: *job-linux-4c
 
@@ -668,9 +663,6 @@ jobs:
                 --enable-profiler
               SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
-              # Hack around this SDK version, because it doesn't work with clang.
-              # See https://github.com/rust-lang/rust/issues/88796
-              WINDOWS_SDK_20348_HACK: 1
             <<: *job-windows-8c
 
           - name: dist-i686-mingw
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 02b72625d6e..cbb4d5765ca 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -39,11 +39,6 @@ if isMacOS; then
     ciCommandSetEnv AR "ar"
 elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then
 
-    if [[ ${WINDOWS_SDK_20348_HACK-0} -eq 1 ]]; then
-        rm -rf '/c/Program Files (x86)/Windows Kits/10/include/10.0.20348.0'
-        mv '/c/Program Files (x86)/Windows Kits/10/include/'10.0.{19041,20348}.0
-    fi
-
     # If we're compiling for MSVC then we, like most other distribution builders,
     # switch to clang as the compiler. This'll allow us eventually to enable LTO
     # amongst LLVM and rustc. Note that we only do this on MSVC as I don't think
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 1ea0178266b3f3f613b0fabdaf16a83961c99cd
+Subproject 9cd5c5a6ccbd4c07c65ab5c69a53286280308c9
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 8a87926a985ce32ca1fad1be4008ee161a0b91e
+Subproject 07e0df2f006e59d171c6bf3cafa9d61dbeb520d
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject b5a12d95e32ae53791cc6ab44417774667ed2ac
+Subproject 24eebb6df96d037aad285e4f7793bd0393a6687
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index db4a26937d5..1b791f5eb36 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -101,7 +101,7 @@ target | notes
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
-`x86_64-unknown-netbsd` | NetBSD/amd64
+[`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64
 
 ## Tier 2
 
@@ -128,7 +128,7 @@ target | std | notes
 `aarch64-apple-ios` | ✓ | ARM64 iOS
 [`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
 `aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia`
-`aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia
+[`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
 `aarch64-unknown-none` | * | Bare ARM64, hardfloat
@@ -159,7 +159,7 @@ target | std | notes
 `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
 `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
 `mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+[`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
 `riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
 `riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
 `riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
@@ -183,7 +183,7 @@ target | std | notes
 `x86_64-apple-ios` | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
-`x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia
+[`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
@@ -309,6 +309,7 @@ target | std | host | notes
 `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
+[`riscv64-linux-android`](platform-support/android.md) |   |   | RISC-V 64-bit Android
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
@@ -337,6 +338,6 @@ target | std | host | notes
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 `x86_64-wrs-vxworks` | ? |  |
-`x86_64h-apple-darwin` | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
+[`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
index 6bdb3ae26ac..f4d75967370 100644
--- a/src/doc/style-guide/src/README.md
+++ b/src/doc/style-guide/src/README.md
@@ -36,10 +36,10 @@ options.
 
 ### Indentation and line width
 
-* Use spaces, not tabs.
-* Each level of indentation must be 4 spaces (that is, all indentation
+- Use spaces, not tabs.
+- Each level of indentation must be 4 spaces (that is, all indentation
   outside of string literals and comments must be a multiple of 4).
-* The maximum width for a line is 100 characters.
+- The maximum width for a line is 100 characters.
 
 #### Block indent
 
@@ -100,10 +100,12 @@ fn baz() {}
 ```
 
 ### [Module-level items](items.md)
+
 ### [Statements](statements.md)
+
 ### [Expressions](expressions.md)
-### [Types](types.md)
 
+### [Types](types.md)
 
 ### Comments
 
diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md
index 606485bfb6c..64540c3997c 100644
--- a/src/doc/style-guide/src/SUMMARY.md
+++ b/src/doc/style-guide/src/SUMMARY.md
@@ -9,4 +9,5 @@
 - [Other style advice](advice.md)
 - [`Cargo.toml` conventions](cargo.md)
 - [Guiding principles and rationale](principles.md)
+- [Rust style editions](editions.md)
 - [Nightly-only syntax](nightly.md)
diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md
index 9a617be509c..65cf8cb6e90 100644
--- a/src/doc/style-guide/src/advice.md
+++ b/src/doc/style-guide/src/advice.md
@@ -18,16 +18,16 @@ if y {
 
 ## Names
 
- * Types shall be `UpperCamelCase`,
- * Enum variants shall be `UpperCamelCase`,
- * Struct fields shall be `snake_case`,
- * Function and method names shall be `snake_case`,
- * Local variables shall be `snake_case`,
- * Macro names shall be `snake_case`,
- * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`.
- * When a name is forbidden because it is a reserved word (such as `crate`),
-   either use a raw identifier (`r#crate`) or use a trailing underscore
-   (`crate_`). Don't misspell the word (`krate`).
+- Types shall be `UpperCamelCase`,
+- Enum variants shall be `UpperCamelCase`,
+- Struct fields shall be `snake_case`,
+- Function and method names shall be `snake_case`,
+- Local variables shall be `snake_case`,
+- Macro names shall be `snake_case`,
+- Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`.
+- When a name is forbidden because it is a reserved word (such as `crate`),
+  either use a raw identifier (`r#crate`) or use a trailing underscore
+  (`crate_`). Don't misspell the word (`krate`).
 
 ### Modules
 
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
new file mode 100644
index 00000000000..5c67a185b8f
--- /dev/null
+++ b/src/doc/style-guide/src/editions.md
@@ -0,0 +1,46 @@
+# Rust style editions
+
+The default Rust style evolves over time, as Rust does. However, to avoid
+breaking established code style, and CI jobs checking code style, changes to
+the default Rust style only appear in *style editions*.
+
+Code written in a given
+[Rust edition](https://doc.rust-lang.org/edition-guide/)
+uses the corresponding Rust style edition by default. To make it easier to
+migrate code style separately from the semantic changes between Rust editions,
+formatting tools such as `rustfmt` allow updating the style edition separately
+from the Rust edition.
+
+The current version of the style guide describes the latest Rust style edition.
+Each distinct past style will have a corresponding archived version of the
+style guide.
+
+Note that archived versions of the style guide do not document formatting for
+newer Rust constructs that did not exist at the time that version of the style
+guide was archived. However, each style edition will still format all
+constructs valid in that Rust edition, with the style of newer constructs
+coming from the first subsequent style edition providing formatting rules for
+that construct (without any of the systematic/global changes from that style
+edition).
+
+Not all Rust editions have corresponding changes to the Rust style. For
+instance, Rust 2015, Rust 2018, and Rust 2021 all use the same style edition.
+
+## Rust 2024 style edition
+
+This style guide describes the Rust 2024 style edition. The Rust 2024 style
+edition is currently nightly-only and may change before the release of Rust
+2024.
+
+For a full history of changes in the Rust 2024 style edition, see the git
+history of the style guide. Notable changes in the Rust 2024 style edition
+include:
+
+- Miscellaneous `rustfmt` bugfixes.
+
+## Rust 2015/2018/2021 style edition
+
+The archived version of the style guide at
+<https://github.com/rust-lang/rust/tree/37343f4a4d4ed7ad0891cb79e8eb25acf43fb821/src/doc/style-guide/src>
+describes the style edition corresponding to Rust 2015, Rust 2018, and Rust
+2021.
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index f0c2a189f12..32c604f9f3e 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -1,6 +1,6 @@
-## Expressions
+# Expressions
 
-### Blocks
+## Blocks
 
 A block expression must have a newline after the initial `{` and before the
 terminal `}`, unless it qualifies to be written as a single line based on
@@ -63,10 +63,10 @@ Write an empty block as `{}`.
 
 Write a block on a single line if:
 
-* it is either used in expression position (not statement position) or is an
+- it is either used in expression position (not statement position) or is an
   unsafe block in statement position,
-* it contains a single-line expression and no statements, and
-* it contains no comments
+- it contains a single-line expression and no statements, and
+- it contains no comments
 
 For a single-line block, put spaces after the opening brace and before the
 closing brace.
@@ -116,8 +116,7 @@ fn main() {
 }
 ```
 
-
-### Closures
+## Closures
 
 Don't put any extra spaces before the first `|` (unless the closure is prefixed
 by a keyword such as `move`); put a space between the second `|` and the
@@ -155,8 +154,7 @@ move |arg1: i32, arg2: i32| -> i32 {
 }
 ```
 
-
-### Struct literals
+## Struct literals
 
 If a struct literal is *small*, format it on a single line, and do not use a
 trailing comma. If not, split it across multiple lines, with each field on its
@@ -185,8 +183,7 @@ let f = Foo {
 };
 ```
 
-
-### Tuple literals
+## Tuple literals
 
 Use a single-line form where possible. Do not put spaces between the opening
 parenthesis and the first element, or between the last element and the closing
@@ -205,8 +202,7 @@ let x = (
 );
 ```
 
-
-### Tuple struct literals
+## Tuple struct literals
 
 Do not put space between the identifier and the opening parenthesis. Otherwise,
 follow the rules for tuple literals:
@@ -220,8 +216,7 @@ let x = Foo(
 );
 ```
 
-
-### Enum literals
+## Enum literals
 
 Follow the formatting rules for the various struct literals. Prefer using the
 name of the enum as a qualifying name, unless the enum is in the prelude:
@@ -235,8 +230,7 @@ Foo::Baz {
 Ok(an_expr)
 ```
 
-
-### Array literals
+## Array literals
 
 Write small array literals on a single line. Do not put spaces between the opening
 square bracket and the first element, or between the last element and the closing
@@ -276,8 +270,7 @@ fn main() {
 }
 ```
 
-
-### Array accesses, indexing, and slicing.
+## Array accesses, indexing, and slicing
 
 Don't put spaces around the square brackets. Avoid breaking lines if possible.
 Never break a line between the target expression and the opening square
@@ -300,13 +293,13 @@ fn main() {
 }
 ```
 
-### Unary operations
+## Unary operations
 
 Do not include a space between a unary op and its operand (i.e., `!x`, not
 `! x`). However, there must be a space after `&mut`. Avoid line-breaking
 between a unary operator and its operand.
 
-### Binary operations
+## Binary operations
 
 Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=`
 and other assignment operators such as `+=` or `*=`).
@@ -335,7 +328,7 @@ foo_bar
 Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
 than at other binary operators.
 
-### Control flow
+## Control flow
 
 Do not include extraneous parentheses for `if` and `while` expressions.
 
@@ -354,7 +347,7 @@ if (true) {
 Do include extraneous parentheses if it makes an arithmetic or logic expression
 easier to understand (`(x * 15) + (y * 20)` is fine)
 
-### Function calls
+## Function calls
 
 Do not put a space between the function name, and the opening parenthesis.
 
@@ -364,7 +357,7 @@ Do put a space between an argument, and the comma which precedes it.
 
 Prefer not to break a line in the callee expression.
 
-#### Single-line calls
+### Single-line calls
 
 Do not put a space between the function name and open paren, between the open
 paren and the first argument, or between the last argument and the close paren.
@@ -375,7 +368,7 @@ Do not put a comma after the last argument.
 foo(x, y, z)
 ```
 
-#### Multi-line calls
+### Multi-line calls
 
 If the function call is not *small*, it would otherwise over-run the max width,
 or any argument or the callee is multi-line, then format the call across
@@ -390,8 +383,7 @@ a_function_call(
 )
 ```
 
-
-### Method calls
+## Method calls
 
 Follow the function rules for calling.
 
@@ -401,15 +393,14 @@ Do not put any spaces around the `.`.
 x.foo().bar().baz(x, y, z);
 ```
 
-
-### Macro uses
+## Macro uses
 
 If a macro can be parsed like other constructs, format it like those
 constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
 function call (ignoring the `!`), so format it using the rules for function
 calls.
 
-#### Special case macros
+### Special case macros
 
 For macros which take a format string, if all other arguments are *small*,
 format the arguments before the format string on a single line if they fit, and
@@ -430,8 +421,7 @@ assert_eq!(
 );
 ```
 
-
-### Casts (`as`)
+## Casts (`as`)
 
 Put spaces before and after `as`:
 
@@ -439,8 +429,7 @@ Put spaces before and after `as`:
 let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char;
 ```
 
-
-### Chains of fields and method calls
+## Chains of fields and method calls
 
 A chain is a sequence of field accesses, method calls, and/or uses of the try
 operator `?`. E.g., `a.b.c().d` or `foo?.bar().baz?`.
@@ -478,7 +467,7 @@ foo(
     .qux();
 ```
 
-#### Multi-line elements
+### Multi-line elements
 
 If any element in a chain is formatted across multiple lines, put that element
 and any later elements on their own lines.
@@ -513,7 +502,7 @@ self.pre_comment.as_ref().map_or(
 )
 ```
 
-### Control flow expressions
+## Control flow expressions
 
 This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
 expressions.
@@ -584,8 +573,7 @@ if !self.config.file_lines().intersects(
 }
 ```
 
-
-#### Single line `if else`
+### Single line `if else`
 
 Put an `if else` or `if let else` on a single line if it occurs in expression
 context (i.e., is not a standalone statement), it contains a single `else`
@@ -608,8 +596,7 @@ if x {
 }
 ```
 
-
-### Match
+## Match
 
 Prefer not to line-break inside the discriminant expression. Always break after
 the opening brace and before the closing brace. Block-indent the match arms
@@ -718,7 +705,7 @@ match foo {
 }
 ```
 
-#### Line-breaking
+### Line-breaking
 
 If using a block form on the right-hand side of a match arm makes it possible
 to avoid breaking on the left-hand side, do that:
@@ -812,8 +799,7 @@ small_no_tuple:
 
 E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
 
-
-### Combinable expressions
+## Combinable expressions
 
 Where a function call has a single argument, and that argument is formatted
 across multiple-lines, format the outer call as if it were a single-line call,
@@ -861,8 +847,7 @@ foo(first_arg, x, |param| {
 })
 ```
 
-
-### Ranges
+## Ranges
 
 Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`.
 
@@ -879,8 +864,7 @@ For the sake of indicating precedence, if either bound is a compound
 expression, use parentheses around it, e.g., `..(x + 1)`, `(x.f)..(x.f.len())`,
 or `0..(x - 10)`.
 
-
-### Hexadecimal literals
+## Hexadecimal literals
 
 Hexadecimal literals may use upper- or lower-case letters, but they must not be
 mixed within the same literal. Projects should use the same case for all
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index 6e5ea335e6a..a6d941f6d04 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -1,4 +1,4 @@
-## Items
+# Items
 
 Items consist of the set of things permitted at the top level of a module.
 However, Rust also allows some items to appear within some other types of
@@ -16,7 +16,7 @@ names.
 Don't automatically move module declarations annotated with `#[macro_use]`,
 since that might change semantics.
 
-### Function definitions
+## Function definitions
 
 In Rust, people often find functions by searching for `fn [function-name]`, so
 the formatting of function definitions must enable this.
@@ -46,14 +46,13 @@ fn foo(
 
 Note the trailing comma on the last argument.
 
-
-### Tuples and tuple structs
+## Tuples and tuple structs
 
 Write the type list as you would a parameter list to a function.
 
 Build a tuple or tuple struct as you would call a function.
 
-#### Single-line
+### Single-line
 
 ```rust
 struct Bar(Type1, Type2);
@@ -62,7 +61,7 @@ let x = Bar(11, 22);
 let y = (11, 22, 33);
 ```
 
-### Enums
+## Enums
 
 In the declaration, put each variant on its own line, block indented.
 
@@ -96,8 +95,7 @@ multiple lines, use the multi-line formatting for all struct variants. However,
 such a situation might be an indication that you should factor out the fields
 of the variant into their own struct.
 
-
-### Structs and Unions
+## Structs and Unions
 
 Struct names follow on the same line as the `struct` keyword, with the opening
 brace on the same line when it fits within the right margin. All struct fields
@@ -138,8 +136,7 @@ union Foo {
 }
 ```
 
-
-### Tuple structs
+## Tuple structs
 
 Put the whole struct on one line if possible. Separate types within the
 parentheses using a comma and space. Don't use a trailing comma for a
@@ -165,8 +162,7 @@ pub struct Foo(
 );
 ```
 
-
-### Traits
+## Traits
 
 Use block-indent for trait items. If there are no items, format the trait (including its `{}`)
 on a single line. Otherwise, break after the opening brace and before
@@ -204,8 +200,7 @@ pub trait IndexRanges:
 }
 ```
 
-
-### Impls
+## Impls
 
 Use block-indent for impl items. If there are no items, format the impl
 (including its `{}`) on a single line. Otherwise, break after the opening brace
@@ -231,15 +226,13 @@ impl Bar
 }
 ```
 
-
-### Extern crate
+## Extern crate
 
 `extern crate foo;`
 
 Use spaces around keywords, no spaces around the semicolon.
 
-
-### Modules
+## Modules
 
 ```rust
 mod foo {
@@ -253,7 +246,7 @@ mod foo;
 Use spaces around keywords and before the opening brace, no spaces around the
 semicolon.
 
-### macro\_rules!
+## `macro_rules!`
 
 Use `{}` for the full definition of the macro.
 
@@ -262,8 +255,7 @@ macro_rules! foo {
 }
 ```
 
-
-### Generics
+## Generics
 
 Prefer to put a generics clause on one line. Break other parts of an item
 declaration rather than line-breaking a generics clause. If a generics clause is
@@ -299,8 +291,7 @@ If an associated type is bound in a generic type, put spaces around the `=`:
 
 Prefer to use single-letter names for generic parameters.
 
-
-### `where` clauses
+## `where` clauses
 
 These rules apply for `where` clauses on any item.
 
@@ -373,7 +364,7 @@ where
         + Index<RangeFull>,
 ```
 
-### Type aliases
+## Type aliases
 
 Keep type aliases on one line when they fit. If necessary to break the line, do
 so after the `=`, and block-indent the right-hand side:
@@ -398,8 +389,7 @@ where
 = AnEvenLongerType<T, U, Foo<T>>;
 ```
 
-
-### Associated types
+## Associated types
 
 Format associated types like type aliases. Where an associated type has a
 bound, put a space after the colon but not before:
@@ -408,15 +398,13 @@ bound, put a space after the colon but not before:
 pub type Foo: Bar;
 ```
 
-
-### extern items
+## extern items
 
 When writing extern items (such as `extern "C" fn`), always specify the ABI.
 For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or
 `extern "C" { ... }`.
 
-
-### Imports (`use` statements)
+## Imports (`use` statements)
 
 Format imports on one line where possible. Don't put spaces around braces.
 
@@ -426,8 +414,7 @@ use a::b::d::*;
 use a::b::{foo, bar, baz};
 ```
 
-
-#### Large list imports
+### Large list imports
 
 Prefer to use multiple imports rather than a multi-line import. However, tools
 should not split imports by default.
@@ -437,7 +424,6 @@ does not fit within the max width, or because of the rules for nested imports
 below), then break after the opening brace and before the closing brace, use a
 trailing comma, and block indent the names.
 
-
 ```rust
 // Prefer
 foo::{long, list, of, imports};
@@ -450,8 +436,7 @@ foo::{
 };
 ```
 
-
-#### Ordering of imports
+### Ordering of imports
 
 A *group* of imports is a set of imports on the same or sequential lines. One or
 more blank lines or other items (e.g., a function) separate groups of imports.
@@ -459,7 +444,6 @@ more blank lines or other items (e.g., a function) separate groups of imports.
 Within a group of imports, imports must be sorted ASCIIbetically (uppercase
 before lowercase). Groups of imports must not be merged or re-ordered.
 
-
 E.g., input:
 
 ```rust
@@ -483,27 +467,25 @@ use b;
 Because of `macro_use`, attributes must also start a new group and prevent
 re-ordering.
 
-#### Ordering list import
+### Ordering list import
 
 Names in a list import must be sorted ASCIIbetically, but with `self` and
 `super` first, and groups and glob imports last. This applies recursively. For
 example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
 `use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
 
-
-#### Normalisation
+### Normalisation
 
 Tools must make the following normalisations, recursively:
 
-* `use a::self;` -> `use a;`
-* `use a::{};` -> (nothing)
-* `use a::{b};` -> `use a::b;`
+- `use a::self;` -> `use a;`
+- `use a::{};` -> (nothing)
+- `use a::{b};` -> `use a::b;`
 
 Tools must not otherwise merge or un-merge import lists or adjust glob imports
 (without an explicit option).
 
-
-#### Nested imports
+### Nested imports
 
 If there are any nested imports in a list import, then use the multi-line form,
 even if the import fits on one line. Each nested import must be on its own line,
@@ -519,8 +501,7 @@ use a::b::{
 };
 ```
 
-
-#### Merging/un-merging imports
+### Merging/un-merging imports
 
 An example:
 
diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md
index 031811b0e6f..66e7fa3c9f8 100644
--- a/src/doc/style-guide/src/nightly.md
+++ b/src/doc/style-guide/src/nightly.md
@@ -1,3 +1,5 @@
+# Nightly
+
 This chapter documents style and formatting for nightly-only syntax. The rest of the style guide documents style for stable Rust syntax; nightly syntax only appears in this chapter. Each section here includes the name of the feature gate, so that searches (e.g. `git grep`) for a nightly feature in the Rust repository also turn up the style guide section.
 
 Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization.
diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md
index d548693e39e..ce57c649a2d 100644
--- a/src/doc/style-guide/src/principles.md
+++ b/src/doc/style-guide/src/principles.md
@@ -3,27 +3,27 @@
 When deciding on style guidelines, the style team follows these guiding
 principles (in rough priority order):
 
-* readability
-    - scan-ability
-    - avoiding misleading formatting
-    - accessibility - readable and editable by users using the widest
-      variety of hardware, including non-visual accessibility interfaces
-    - readability of code in contexts without syntax highlighting or IDE
-      assistance, such as rustc error messages, diffs, grep, and other
-      plain-text contexts
+- readability
+  - scan-ability
+  - avoiding misleading formatting
+  - accessibility - readable and editable by users using the widest
+    variety of hardware, including non-visual accessibility interfaces
+  - readability of code in contexts without syntax highlighting or IDE
+    assistance, such as rustc error messages, diffs, grep, and other
+    plain-text contexts
 
-* aesthetics
-    - sense of 'beauty'
-    - consistent with other languages/tools
+- aesthetics
+  - sense of 'beauty'
+  - consistent with other languages/tools
 
-* specifics
-    - compatibility with version control practices - preserving diffs,
-      merge-friendliness, etc.
-    - preventing rightward drift
-    - minimising vertical space
+- specifics
+  - compatibility with version control practices - preserving diffs,
+    merge-friendliness, etc.
+  - preventing rightward drift
+  - minimising vertical space
 
-* application
-    - ease of manual application
-    - ease of implementation (in `rustfmt`, and in other tools/editors/code generators)
-    - internal consistency
-    - simplicity of formatting rules
+- application
+  - ease of manual application
+  - ease of implementation (in `rustfmt`, and in other tools/editors/code generators)
+  - internal consistency
+  - simplicity of formatting rules
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 8c8f893fbe9..6f322b3d65b 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -1,6 +1,6 @@
-## Statements
+# Statements
 
-### Let statements
+## Let statements
 
 Put a space after the `:` and on both sides of the `=` (if they are present).
 Don't put a space before the semicolon.
@@ -28,7 +28,6 @@ use block indentation. If the type requires multiple lines, even after
 line-breaking after the `:`, then place the first line on the same line as the
 `:`, subject to the [combining rules](expressions.html#combinable-expressions).
 
-
 ```rust
 let pattern:
     Type =
@@ -101,7 +100,7 @@ let Foo {
 );
 ```
 
-#### else blocks (let-else statements)
+### else blocks (let-else statements)
 
 A let statement can contain an `else` component, making it a let-else statement.
 In this case, always apply the same formatting rules to the components preceding
@@ -231,7 +230,7 @@ fn main() {
 }
 ```
 
-### Macros in statement position
+## Macros in statement position
 
 For a macro use in statement position, use parentheses or square brackets as
 delimiters, and terminate it with a semicolon. Do not put spaces around the
@@ -242,8 +241,7 @@ name, `!`, the delimiters, or the `;`.
 a_macro!(...);
 ```
 
-
-### Expressions in statement position
+## Expressions in statement position
 
 Do not put space between the expression and the semicolon.
 
diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md
index 15b001d4f2e..b7921c8914e 100644
--- a/src/doc/style-guide/src/types.md
+++ b/src/doc/style-guide/src/types.md
@@ -1,23 +1,22 @@
-## Types and Bounds
-
-### Single line formatting
-
-* `[T]` no spaces
-* `[T; expr]`, e.g., `[u32; 42]`, `[Vec<Foo>; 10 * 2 + foo()]` (space after colon, no spaces around square brackets)
-* `*const T`, `*mut T` (no space after `*`, space before type)
-* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words)
-* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keywords and sigils, and after commas, no trailing commas, no spaces around brackets)
-* `!` gets treated like any other type name, `Name`
-* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple)
-* `<Baz<T> as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`)
-* `Foo::Bar<T, U, V>` (spaces after commas, no trailing comma, no spaces around angle brackets)
-* `T + T + T` (single spaces between types, and `+`).
-* `impl T + T + T` (single spaces between keyword, types, and `+`).
+# Types and Bounds
+
+## Single line formatting
+
+- `[T]` no spaces
+- `[T; expr]`, e.g., `[u32; 42]`, `[Vec<Foo>; 10 * 2 + foo()]` (space after colon, no spaces around square brackets)
+- `*const T`, `*mut T` (no space after `*`, space before type)
+- `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words)
+- `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keywords and sigils, and after commas, no trailing commas, no spaces around brackets)
+- `!` gets treated like any other type name, `Name`
+- `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple)
+- `<Baz<T> as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`)
+- `Foo::Bar<T, U, V>` (spaces after commas, no trailing comma, no spaces around angle brackets)
+- `T + T + T` (single spaces between types, and `+`).
+- `impl T + T + T` (single spaces between keyword, types, and `+`).
 
 Do not put space around parentheses used in types, e.g., `(Foo)`
 
-
-### Line breaks
+## Line breaks
 
 Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer
 
diff --git a/src/doc/unstable-book/src/compiler-flags/no-parallel-llvm.md b/src/doc/unstable-book/src/compiler-flags/no-parallel-llvm.md
new file mode 100644
index 00000000000..f19ba16b6f7
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/no-parallel-llvm.md
@@ -0,0 +1,8 @@
+# `no-parallel-llvm`
+
+---------------------
+
+This flag disables parallelization of codegen and linking, while otherwise preserving
+behavior with regard to codegen units and LTO.
+
+This flag is not useful for regular users, but it can be useful for debugging the backend. Codegen issues commonly only manifest under specific circumstances, e.g. if multiple codegen units are used and ThinLTO is enabled. Serialization of these threaded configurations makes the use of LLVM debugging facilities easier, by avoiding the interleaving of output.
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 9f65f1eeeb7..238b5aa4d5a 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -18,7 +18,7 @@ complete -c x.py -n "__fish_use_subcommand" -l llvm-skip-rebuild -d 'whether reb
 complete -c x.py -n "__fish_use_subcommand" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_use_subcommand" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_use_subcommand" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_use_subcommand" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_use_subcommand" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_use_subcommand" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_use_subcommand" -s i -l incremental -d 'use incremental compilation'
@@ -26,7 +26,6 @@ complete -c x.py -n "__fish_use_subcommand" -l include-default-paths -d 'include
 complete -c x.py -n "__fish_use_subcommand" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_use_subcommand" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_use_subcommand" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_use_subcommand" -s h -l help -d 'Print help'
 complete -c x.py -n "__fish_use_subcommand" -f -a "build" -d 'Compile either the compiler or libraries'
 complete -c x.py -n "__fish_use_subcommand" -f -a "check" -d 'Compile either the compiler or libraries, using cargo check'
@@ -62,7 +61,7 @@ complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from build" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from build" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from build" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from build" -s i -l incremental -d 'use incremental compilation'
@@ -70,7 +69,6 @@ complete -c x.py -n "__fish_seen_subcommand_from build" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from build" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from build" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from build" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from check" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -92,7 +90,7 @@ complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from check" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from check" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from check" -l all-targets -d 'Check all targets'
 complete -c x.py -n "__fish_seen_subcommand_from check" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
@@ -101,7 +99,6 @@ complete -c x.py -n "__fish_seen_subcommand_from check" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from check" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from check" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from check" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -s A -d 'clippy lints to allow' -r
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -s D -d 'clippy lints to deny' -r
@@ -127,7 +124,7 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from clippy" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l fix
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
@@ -136,7 +133,6 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l include-default-path
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from clippy" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -158,7 +154,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-skip-rebuild -d 'w
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from fix" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from fix" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from fix" -s i -l incremental -d 'use incremental compilation'
@@ -166,7 +162,6 @@ complete -c x.py -n "__fish_seen_subcommand_from fix" -l include-default-paths -
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from fix" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -188,7 +183,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-skip-rebuild -d 'w
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from fmt" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l check -d 'check formatting instead of applying'
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
@@ -197,7 +192,6 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l include-default-paths -
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from fmt" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -219,7 +213,7 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-skip-rebuild -d 'w
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from doc" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l open -d 'open the docs in a browser'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l json -d 'render the documentation in JSON format in addition to the usual HTML format'
@@ -229,7 +223,6 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l include-default-paths -
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
@@ -257,7 +250,7 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-skip-rebuild -d '
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from test" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l no-fail-fast -d 'run all tests regardless of failure'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l no-doc -d 'do not run doc tests'
@@ -272,7 +265,6 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from test" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l test-args -r
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l config -d 'TOML configuration file for build' -r -F
@@ -295,7 +287,7 @@ complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from bench" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from bench" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from bench" -s i -l incremental -d 'use incremental compilation'
@@ -303,8 +295,8 @@ complete -c x.py -n "__fish_seen_subcommand_from bench" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from bench" -s h -l help -d 'Print help'
+complete -c x.py -n "__fish_seen_subcommand_from clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l build -d 'build target of the stage0 compiler' -r -f
@@ -313,7 +305,6 @@ complete -c x.py -n "__fish_seen_subcommand_from clean" -l target -d 'target tar
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l exclude -d 'build paths to exclude' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l rustc-error-format -r -f
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
-complete -c x.py -n "__fish_seen_subcommand_from clean" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)"
@@ -325,16 +316,15 @@ complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from clean" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l set -d 'override options in config.toml' -r -f
-complete -c x.py -n "__fish_seen_subcommand_from clean" -l all
+complete -c x.py -n "__fish_seen_subcommand_from clean" -l all -d 'Clean the entire build directory (not used by default)'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -s i -l incremental -d 'use incremental compilation'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l include-default-paths -d 'include default paths in addition to the provided ones'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from clean" -s h -l help -d 'Print help'
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -356,7 +346,7 @@ complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-skip-rebuild -d '
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from dist" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from dist" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from dist" -s i -l incremental -d 'use incremental compilation'
@@ -364,7 +354,6 @@ complete -c x.py -n "__fish_seen_subcommand_from dist" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from dist" -s h -l help -d 'Print help'
 complete -c x.py -n "__fish_seen_subcommand_from install" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -386,7 +375,7 @@ complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-skip-rebuild -
 complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from install" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from install" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from install" -s i -l incremental -d 'use incremental compilation'
@@ -394,7 +383,6 @@ complete -c x.py -n "__fish_seen_subcommand_from install" -l include-default-pat
 complete -c x.py -n "__fish_seen_subcommand_from install" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from install" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help'
 complete -c x.py -n "__fish_seen_subcommand_from run" -l args -d 'arguments for the tool' -r
 complete -c x.py -n "__fish_seen_subcommand_from run" -l config -d 'TOML configuration file for build' -r -F
@@ -417,7 +405,7 @@ complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-skip-rebuild -d 'w
 complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from run" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from run" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from run" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from run" -s i -l incremental -d 'use incremental compilation'
@@ -425,7 +413,6 @@ complete -c x.py -n "__fish_seen_subcommand_from run" -l include-default-paths -
 complete -c x.py -n "__fish_seen_subcommand_from run" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from run" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from run" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -447,7 +434,7 @@ complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-skip-rebuild -d
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from setup" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from setup" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_seen_subcommand_from setup" -s i -l incremental -d 'use incremental compilation'
@@ -455,7 +442,6 @@ complete -c x.py -n "__fish_seen_subcommand_from setup" -l include-default-paths
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from setup" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
@@ -477,7 +463,7 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-skip-rebuild -
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
-complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l set -d 'override options in config.toml' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l run -d 'run suggested tests'
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
@@ -486,5 +472,4 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l include-default-pat
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l dry-run -d 'dry run; don\'t build anything'
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l json-output -d 'use message-format=json'
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
-complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build'
 complete -c x.py -n "__fish_seen_subcommand_from suggest" -s h -l help -d 'Print help (see more with \'--help\')'
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 569c186555c..ff7d49d5e30 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -42,7 +42,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -52,7 +52,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries')
@@ -93,7 +92,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -103,7 +102,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -130,7 +128,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--all-targets', 'all-targets', [CompletionResultType]::ParameterName, 'Check all targets')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -141,7 +139,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -172,7 +169,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--fix', 'fix', [CompletionResultType]::ParameterName, 'fix')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -183,7 +180,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -210,7 +206,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -220,7 +216,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -247,7 +242,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'check formatting instead of applying')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -258,7 +253,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -285,7 +279,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'open the docs in a browser')
             [CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'render the documentation in JSON format in addition to the usual HTML format')
@@ -297,7 +291,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -330,7 +323,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--no-fail-fast', 'no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure')
             [CompletionResult]::new('--no-doc', 'no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests')
@@ -347,7 +340,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -375,7 +367,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -385,12 +377,12 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
             break
         }
         'x.py;clean' {
+            [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used')
             [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`')
             [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
@@ -399,7 +391,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
             [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format')
             [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
-            [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
             [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
             [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
             [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout')
@@ -412,9 +403,9 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
-            [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'all')
+            [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'Clean the entire build directory (not used by default)')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation')
@@ -423,7 +414,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
             break
@@ -450,7 +440,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -460,7 +450,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
             break
@@ -487,7 +476,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -497,7 +486,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
             break
@@ -525,7 +513,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -535,7 +523,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -562,7 +549,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -572,7 +559,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
@@ -599,7 +585,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
             [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
             [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
-            [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
             [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
             [CompletionResult]::new('--run', 'run', [CompletionResultType]::ParameterName, 'run suggested tests')
             [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
@@ -610,7 +596,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
             [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
             [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
-            [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build')
             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 322afdb2883..4e9286ae1e8 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -61,7 +61,7 @@ _x.py() {
 
     case "${cmd}" in
         x.py)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest"
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest"
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -151,7 +151,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -167,7 +167,7 @@ _x.py() {
             return 0
             ;;
         x.py__bench)
-            opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -261,7 +261,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -277,7 +277,7 @@ _x.py() {
             return 0
             ;;
         x.py__build)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -367,7 +367,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -383,7 +383,7 @@ _x.py() {
             return 0
             ;;
         x.py__check)
-            opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -473,7 +473,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -489,12 +489,16 @@ _x.py() {
             return 0
             ;;
         x.py__clean)
-            opts="-v -i -j -h --all --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
             fi
             case "${prev}" in
+                --stage)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --config)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -527,10 +531,6 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --stage)
-                    COMPREPLY=("${cur}")
-                    return 0
-                    ;;
                 --keep-stage)
                     COMPREPLY=("${cur}")
                     return 0
@@ -579,7 +579,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -595,7 +595,7 @@ _x.py() {
             return 0
             ;;
         x.py__clippy)
-            opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -701,7 +701,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -717,7 +717,7 @@ _x.py() {
             return 0
             ;;
         x.py__dist)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -807,7 +807,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -823,7 +823,7 @@ _x.py() {
             return 0
             ;;
         x.py__doc)
-            opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -913,7 +913,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -929,7 +929,7 @@ _x.py() {
             return 0
             ;;
         x.py__fix)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1019,7 +1019,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1035,7 +1035,7 @@ _x.py() {
             return 0
             ;;
         x.py__fmt)
-            opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1125,7 +1125,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1141,7 +1141,7 @@ _x.py() {
             return 0
             ;;
         x.py__install)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1231,7 +1231,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1247,7 +1247,7 @@ _x.py() {
             return 0
             ;;
         x.py__run)
-            opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1341,7 +1341,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1357,7 +1357,7 @@ _x.py() {
             return 0
             ;;
         x.py__setup)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1447,7 +1447,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1463,7 +1463,7 @@ _x.py() {
             return 0
             ;;
         x.py__suggest)
-            opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1553,7 +1553,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
@@ -1569,7 +1569,7 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1683,7 +1683,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --llvm-bolt-profile-use)
+                --reproducible-artifact)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index d9c4645f0b3..6e5e2c35005 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -31,5 +31,8 @@
         "--json-output"
     ],
     "rust-analyzer.cargo.sysrootSrc": "./library",
-    "rust-analyzer.rustc.source": "./Cargo.toml"
+    "rust-analyzer.rustc.source": "./Cargo.toml",
+    "rust-analyzer.cargo.extraEnv": {
+        "RUSTC_BOOTSTRAP": "1"
+    }
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9839b82d7d7..6ec8f516366 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2809,7 +2809,7 @@ fn clean_use_statement_inner<'tcx>(
     cx: &mut DocContext<'tcx>,
     inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
 ) -> Vec<Item> {
-    if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
+    if should_ignore_res(path.res) {
         return Vec::new();
     }
     // We need this comparison because some imports (for std types for example)
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 5c8db3b8774..baf90b6d73e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -13,7 +13,7 @@ use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenTree;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt};
@@ -629,3 +629,35 @@ pub(super) fn display_macro_source(
         }
     }
 }
+
+pub(crate) fn inherits_doc_hidden(
+    tcx: TyCtxt<'_>,
+    mut def_id: LocalDefId,
+    stop_at: Option<LocalDefId>,
+) -> bool {
+    let hir = tcx.hir();
+    while let Some(id) = tcx.opt_local_parent(def_id) {
+        if let Some(stop_at) = stop_at && id == stop_at {
+            return false;
+        }
+        def_id = id;
+        if tcx.is_doc_hidden(def_id.to_def_id()) {
+            return true;
+        } else if let Some(node) = hir.find_by_def_id(def_id) &&
+            matches!(
+                node,
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
+            )
+        {
+            // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
+            // on them, they don't inherit it from the parent context.
+            return false;
+        }
+    }
+    false
+}
+
+#[inline]
+pub(crate) fn should_ignore_res(res: Res) -> bool {
+    matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..))
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index fd00277e213..3fb7122fad3 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -532,8 +532,6 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
             let start_tags = format!(
                 "<h{level} id=\"{id}\">\
                     <a href=\"#{id}\">",
-                id = id,
-                level = level
             );
             return Some((Event::Html(start_tags.into()), 0..0));
         }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index e05635a0207..db8504d15c7 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -38,7 +38,7 @@ fn test_unique_id() {
     ];
 
     let mut map = IdMap::new();
-    let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
+    let actual: Vec<String> = input.iter().map(|s| map.derive(s)).collect();
     assert_eq!(&actual[..], expected);
 }
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 037c88cb85d..991edbddc6f 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -162,7 +162,7 @@ impl<'tcx> Context<'tcx> {
         self.shared.tcx.sess
     }
 
-    pub(super) fn derive_id(&mut self, id: String) -> String {
+    pub(super) fn derive_id<S: AsRef<str> + ToString>(&mut self, id: S) -> String {
         self.id_map.derive(id)
     }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a6200654ffa..8a6e0b1ed51 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -268,7 +268,7 @@ impl AllTypes {
     fn append(&mut self, item_name: String, item_type: &ItemType) {
         let mut url: Vec<_> = item_name.split("::").skip(1).collect();
         if let Some(name) = url.pop() {
-            let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
+            let new_url = format!("{}/{item_type}.{name}.html", url.join("/"));
             url.push(name);
             let name = url.join("::");
             match *item_type {
@@ -385,16 +385,17 @@ impl AllTypes {
 fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
     let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
     content.push_str(&format!(
-      "## More information\n\n\
-      If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
-      DOC_RUST_LANG_ORG_CHANNEL));
+        "## More information\n\n\
+      If you want more information about this feature, please read the [corresponding chapter in \
+      the Rustdoc book]({DOC_RUST_LANG_ORG_CHANNEL}/rustdoc/scraped-examples.html)."
+    ));
 
     let mut ids = IdMap::default();
     format!(
         "<div class=\"main-heading\">\
-            <h1>About scraped examples</h1>\
-        </div>\
-        <div>{}</div>",
+             <h1>About scraped examples</h1>\
+         </div>\
+         <div>{}</div>",
         Markdown {
             content: &content,
             links: &[],
@@ -473,7 +474,7 @@ fn document_short<'a, 'cx: 'a>(
                 MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
 
             if has_more_content {
-                let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
+                let link = format!(" <a{}>Read more</a>", assoc_href_attr(item, link, cx));
 
                 if let Some(idx) = summary_html.rfind("</p>") {
                     summary_html.insert_str(idx, &link);
@@ -482,7 +483,7 @@ fn document_short<'a, 'cx: 'a>(
                 }
             }
 
-            write!(f, "<div class='docblock'>{}</div>", summary_html)?;
+            write!(f, "<div class='docblock'>{summary_html}</div>")?;
         }
         Ok(())
     })
@@ -517,9 +518,9 @@ fn document_full_inner<'a, 'cx: 'a>(
                 write!(
                     f,
                     "<details class=\"toggle top-doc\" open>\
-                    <summary class=\"hideme\">\
+                     <summary class=\"hideme\">\
                         <span>Expand description</span>\
-                    </summary>{}</details>",
+                     </summary>{}</details>",
                     render_markdown(cx, &s, item.links(cx), heading_offset)
                 )?;
             } else {
@@ -701,8 +702,8 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
     let item_type = it.type_();
 
     let href = match link {
-        AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
-        AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
+        AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{id}")),
+        AssocItemLink::Anchor(None) => Some(format!("#{item_type}.{name}")),
         AssocItemLink::GotoSource(did, provided_methods) => {
             // We're creating a link from the implementation of an associated item to its
             // declaration in the trait declaration.
@@ -722,7 +723,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
             };
 
             match href(did.expect_def_id(), cx) {
-                Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
+                Ok((url, ..)) => Some(format!("{url}#{item_type}.{name}")),
                 // The link is broken since it points to an external crate that wasn't documented.
                 // Do not create any link in such case. This is better than falling back to a
                 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -735,14 +736,14 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
                 // In this scenario, the actual `id` of this impl item would be
                 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
                 Err(HrefError::DocumentationNotBuilt) => None,
-                Err(_) => Some(format!("#{}.{}", item_type, name)),
+                Err(_) => Some(format!("#{item_type}.{name}")),
             }
         }
     };
 
     // If there is no `href` for the reason explained above, simply do not render it which is valid:
     // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
-    href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
+    href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default()
 }
 
 fn assoc_const(
@@ -767,7 +768,7 @@ fn assoc_const(
         ty = ty.print(cx),
     );
     if let Some(default) = default {
-        write!(w, " = ");
+        w.write_str(" = ");
 
         // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
         //        hood which adds noisy underscores and a type suffix to number literals.
@@ -910,39 +911,41 @@ fn render_stability_since_raw_with_extra(
 
     if let Some(ver) = stable_version {
         stability.push_str(ver.as_str());
-        title.push_str(&format!("Stable since Rust version {}", ver));
+        title.push_str(&format!("Stable since Rust version {ver}"));
     }
 
     let const_title_and_stability = match const_stability {
         Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
             if Some(since) != containing_const_ver =>
         {
-            Some((format!("const since {}", since), format!("const: {}", since)))
+            Some((format!("const since {since}"), format!("const: {since}")))
         }
         Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
             let unstable = if let Some(n) = issue {
                 format!(
-                    r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
-                    n, feature
+                    "<a \
+                        href=\"https://github.com/rust-lang/rust/issues/{n}\" \
+                        title=\"Tracking issue for {feature}\"\
+                       >unstable</a>"
                 )
             } else {
                 String::from("unstable")
             };
 
-            Some((String::from("const unstable"), format!("const: {}", unstable)))
+            Some((String::from("const unstable"), format!("const: {unstable}")))
         }
         _ => None,
     };
 
     if let Some((const_title, const_stability)) = const_title_and_stability {
         if !title.is_empty() {
-            title.push_str(&format!(", {}", const_title));
+            title.push_str(&format!(", {const_title}"));
         } else {
             title.push_str(&const_title);
         }
 
         if !stability.is_empty() {
-            stability.push_str(&format!(" ({})", const_stability));
+            stability.push_str(&format!(" ({const_stability})"));
         } else {
             stability.push_str(&const_stability);
         }
@@ -1091,7 +1094,7 @@ pub(crate) fn render_all_impls(
     let impls = impls.into_inner();
     if !impls.is_empty() {
         write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
-        write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls).unwrap();
+        write!(w, "<div id=\"trait-implementations-list\">{impls}</div>").unwrap();
     }
 
     if !synthetic.is_empty() {
@@ -1150,9 +1153,7 @@ fn render_assoc_items_inner(
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id =
                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
-                if let Some(def_id) = type_.def_id(cx.cache()) {
-                    cx.deref_id_map.insert(def_id, id.clone());
-                }
+                let derived_id = cx.derive_id(&id);
                 write_impl_section_heading(
                     &mut tmp_buf,
                     &format!(
@@ -1162,11 +1163,10 @@ fn render_assoc_items_inner(
                     ),
                     &id,
                 );
-                (
-                    RenderMode::ForDeref { mut_: deref_mut_ },
-                    cx.derive_id(id),
-                    r#" class="impl-items""#,
-                )
+                if let Some(def_id) = type_.def_id(cx.cache()) {
+                    cx.deref_id_map.insert(def_id, id);
+                }
+                (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
             }
         };
         let mut impls_buf = Buffer::html();
@@ -1189,10 +1189,13 @@ fn render_assoc_items_inner(
             );
         }
         if !impls_buf.is_empty() {
-            write!(w, "{}", tmp_buf.into_inner()).unwrap();
-            write!(w, "<div id=\"{id}\"{class_html}>").unwrap();
-            write!(w, "{}", impls_buf.into_inner()).unwrap();
-            w.write_str("</div>").unwrap();
+            write!(
+                w,
+                "{}<div id=\"{id}\"{class_html}>{}</div>",
+                tmp_buf.into_inner(),
+                impls_buf.into_inner()
+            )
+            .unwrap();
         }
     }
 
@@ -1392,7 +1395,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
         }
     }
     if out.is_empty() {
-        write!(&mut out, "</code></pre>",);
+        out.write_str("</code></pre>");
     }
 
     (format!("{:#}", ty.print(cx)), out.into_inner())
@@ -1538,25 +1541,25 @@ fn render_impl(
         let toggled = !doc_buffer.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
+            write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
         }
         match &*item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
-                    let id = cx.derive_id(format!("{}.{}", item_type, name));
+                    let id = cx.derive_id(format!("{item_type}.{name}"));
                     let source_id = trait_
                         .and_then(|trait_| {
                             trait_.items.iter().find(|item| {
                                 item.name.map(|n| n.as_str().eq(name.as_str())).unwrap_or(false)
                             })
                         })
-                        .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+                        .map(|item| format!("{}.{name}", item.type_()));
+                    write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
                     render_rightside(w, cx, item, containing_item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
                     }
                     w.write_str("<h4 class=\"code-header\">");
                     render_assoc_item(
@@ -1567,19 +1570,18 @@ fn render_impl(
                         cx,
                         render_mode,
                     );
-                    w.write_str("</h4>");
-                    w.write_str("</section>");
+                    w.write_str("</h4></section>");
                 }
             }
             kind @ (clean::TyAssocConstItem(generics, ty)
             | clean::AssocConstItem(generics, ty, _)) => {
-                let source_id = format!("{}.{}", item_type, name);
-                let id = cx.derive_id(source_id.clone());
-                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+                let source_id = format!("{item_type}.{name}");
+                let id = cx.derive_id(&source_id);
+                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
                 render_rightside(w, cx, item, containing_item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_const(
@@ -1596,16 +1598,15 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4>");
-                w.write_str("</section>");
+                w.write_str("</h4></section>");
             }
             clean::TyAssocTypeItem(generics, bounds) => {
-                let source_id = format!("{}.{}", item_type, name);
-                let id = cx.derive_id(source_id.clone());
-                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+                let source_id = format!("{item_type}.{name}");
+                let id = cx.derive_id(&source_id);
+                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1618,16 +1619,15 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4>");
-                w.write_str("</section>");
+                w.write_str("</h4></section>");
             }
             clean::AssocTypeItem(tydef, _bounds) => {
-                let source_id = format!("{}.{}", item_type, name);
-                let id = cx.derive_id(source_id.clone());
-                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+                let source_id = format!("{item_type}.{name}");
+                let id = cx.derive_id(&source_id);
+                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1640,8 +1640,7 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4>");
-                w.write_str("</section>");
+                w.write_str("</h4></section>");
             }
             clean::StrippedItem(..) => return,
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1744,10 +1743,10 @@ fn render_impl(
             close_tags.insert_str(0, "</details>");
             write!(
                 w,
-                "<details class=\"toggle implementors-toggle\"{}>",
+                "<details class=\"toggle implementors-toggle\"{}>\
+                     <summary>",
                 if rendering_params.toggle_open_by_default { " open" } else { "" }
             );
-            write!(w, "<summary>")
         }
         render_impl_summary(
             w,
@@ -1760,15 +1759,15 @@ fn render_impl(
             aliases,
         );
         if toggled {
-            write!(w, "</summary>")
+            w.write_str("</summary>");
         }
 
         if let Some(ref dox) = i.impl_item.opt_doc_value() {
             if trait_.is_none() && i.inner_impl().items.is_empty() {
                 w.write_str(
                     "<div class=\"item-info\">\
-                    <div class=\"stab empty-impl\">This impl block contains no items.</div>\
-                </div>",
+                         <div class=\"stab empty-impl\">This impl block contains no items.</div>\
+                     </div>",
                 );
             }
             write!(
@@ -1827,11 +1826,11 @@ fn render_rightside(
         const_stable_since,
         if has_src_ref { "" } else { " rightside" },
     );
-    if let Some(l) = src_href {
+    if let Some(link) = src_href {
         if has_stability {
-            write!(rightside, " · <a class=\"src\" href=\"{}\">source</a>", l)
+            write!(rightside, " · <a class=\"src\" href=\"{link}\">source</a>")
         } else {
-            write!(rightside, "<a class=\"src rightside\" href=\"{}\">source</a>", l)
+            write!(rightside, "<a class=\"src rightside\" href=\"{link}\">source</a>")
         }
     }
     if has_stability && has_src_ref {
@@ -1860,10 +1859,13 @@ pub(crate) fn render_impl_summary(
     } else {
         format!(" data-aliases=\"{}\"", aliases.join(","))
     };
-    write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
+    write!(w, "<section id=\"{id}\" class=\"impl\"{aliases}>");
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
-    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
-    write!(w, "<h3 class=\"code-header\">");
+    write!(
+        w,
+        "<a href=\"#{id}\" class=\"anchor\">§</a>\
+         <h3 class=\"code-header\">"
+    );
 
     if let Some(use_absolute) = use_absolute {
         write!(w, "{}", inner_impl.print(use_absolute, cx));
@@ -1888,15 +1890,16 @@ pub(crate) fn render_impl_summary(
     } else {
         write!(w, "{}", inner_impl.print(false, cx));
     }
-    write!(w, "</h3>");
+    w.write_str("</h3>");
 
     let is_trait = inner_impl.trait_.is_some();
     if is_trait {
         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
             write!(
                 w,
-                "<span class=\"item-info\"><div class=\"stab portability\">{}</div></span>",
-                portability
+                "<span class=\"item-info\">\
+                     <div class=\"stab portability\">{portability}</div>\
+                 </span>",
             );
         }
     }
@@ -1949,7 +1952,7 @@ pub(crate) fn small_url_encode(s: String) -> String {
             // consistent with itself when encoding them.
             st += "+";
         } else {
-            write!(st, "%{:02X}", b).unwrap();
+            write!(st, "%{b:02X}").unwrap();
         }
         // Invariant: if the current byte is not at the start of a multi-byte character,
         // we need to get down here so that when the next turn of the loop comes around,
@@ -2264,7 +2267,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
                 format!("lines {}-{}", line_lo + 1, line_hi + 1),
             )
         };
-        let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+        let url = format!("{}{}#{anchor}", cx.root_path(), call_data.url);
         (url, title)
     };
 
@@ -2274,7 +2277,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
             Ok(contents) => contents,
             Err(err) => {
                 let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
-                tcx.sess.span_err(span, format!("failed to read file {}: {}", path.display(), err));
+                tcx.sess.span_err(span, format!("failed to read file {}: {err}", path.display()));
                 return false;
             }
         };
@@ -2333,7 +2336,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
         .unwrap();
 
         if line_ranges.len() > 1 {
-            write!(w, r#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#)
+            w.write_str(r#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#)
                 .unwrap();
         }
 
@@ -2369,7 +2372,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
             highlight::DecorationInfo(decoration_info),
             sources::SourceContext::Embedded { offset: line_min, needs_expansion },
         );
-        write!(w, "</div></div>").unwrap();
+        w.write_str("</div></div>").unwrap();
 
         true
     };
@@ -2436,8 +2439,10 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
 
         // For the remaining examples, generate a <ul> containing links to the source files.
         if it.peek().is_some() {
-            write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#)
-                .unwrap();
+            w.write_str(
+                r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
+            )
+            .unwrap();
             it.for_each(|(_, call_data)| {
                 let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
                 write!(
@@ -2448,11 +2453,11 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
                 )
                 .unwrap();
             });
-            write!(w, "</ul></div>").unwrap();
+            w.write_str("</ul></div>").unwrap();
         }
 
-        write!(w, "</div></details>").unwrap();
+        w.write_str("</div></details>").unwrap();
     }
 
-    write!(w, "</div>").unwrap();
+    w.write_str("</div>").unwrap();
 }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index e363e75f565..cfced799f1e 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -433,7 +433,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                     <a href=\"#{id}\">{name}</a>\
                  </h2>{}",
                 ITEM_TABLE_OPEN,
-                id = cx.derive_id(my_section.id().to_owned()),
+                id = cx.derive_id(my_section.id()),
                 name = my_section.name(),
             );
         }
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 011ca9a4961..e333a35e8ad 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -7,11 +7,11 @@
 
 use super::Pass;
 use crate::clean;
+use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
 use crate::visit::DocVisitor;
-use crate::visit_ast::inherits_doc_hidden;
 use rustc_hir as hir;
 use rustc_middle::lint::LintLevelSource;
 use rustc_session::lint;
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 7b990cd4348..81a90ed498a 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -6,11 +6,11 @@ use rustc_span::symbol::sym;
 use std::mem;
 
 use crate::clean;
+use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::{Item, ItemIdSet};
 use crate::core::DocContext;
 use crate::fold::{strip_item, DocFolder};
 use crate::passes::{ImplStripper, Pass};
-use crate::visit_ast::inherits_doc_hidden;
 
 pub(crate) const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index a6d31534f1d..64a4ace5b9f 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -3,10 +3,10 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{TyCtxt, Visibility};
 use std::mem;
 
+use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::{self, Item, ItemId, ItemIdSet};
 use crate::fold::{strip_item, DocFolder};
 use crate::formats::cache::Cache;
-use crate::visit_ast::inherits_doc_hidden;
 use crate::visit_lib::RustdocEffectiveVisibilities;
 
 pub(crate) struct Stripper<'a, 'tcx> {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 2f67e12df91..3bad9ba4e4a 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -16,6 +16,7 @@ use rustc_span::Span;
 
 use std::mem;
 
+use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
 use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
 use crate::core;
 
@@ -73,33 +74,6 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(
-    tcx: TyCtxt<'_>,
-    mut def_id: LocalDefId,
-    stop_at: Option<LocalDefId>,
-) -> bool {
-    let hir = tcx.hir();
-    while let Some(id) = tcx.opt_local_parent(def_id) {
-        if let Some(stop_at) = stop_at && id == stop_at {
-            return false;
-        }
-        def_id = id;
-        if tcx.is_doc_hidden(def_id.to_def_id()) {
-            return true;
-        } else if let Some(node) = hir.find_by_def_id(def_id) &&
-            matches!(
-                node,
-                hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
-            )
-        {
-            // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
-            // on them, they don't inherit it from the parent context.
-            return false;
-        }
-    }
-    false
-}
-
 pub(crate) struct RustdocVisitor<'a, 'tcx> {
     cx: &'a mut core::DocContext<'tcx>,
     view_item_stack: LocalDefIdSet,
@@ -466,7 +440,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 for &res in &path.res {
                     // Struct and variant constructors and proc macro stubs always show up alongside
                     // their definitions, we've already processed them so just discard these.
-                    if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+                    if should_ignore_res(res) {
                         continue;
                     }
 
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml
index 6c3b5bb00a3..7e0c4bee2b3 100644
--- a/src/tools/build-manifest/Cargo.toml
+++ b/src/tools/build-manifest/Cargo.toml
@@ -8,7 +8,7 @@ toml = "0.5"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 anyhow = "1.0.32"
-flate2 = "1.0.16"
+flate2 = "1.0.26"
 xz2 = "0.1.7"
 tar = "0.4.29"
 sha2 = "0.10.1"
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index 66876e02c19..f20b7a2b4d7 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -78,13 +78,22 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
 /// We will then fall back to origin/master in the hope that at least this exists.
 pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
     let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
-    let upstream_master = format!("{upstream_remote}/master");
-    if rev_exists(&upstream_master, git_dir)? {
-        return Ok(upstream_master);
+    for upstream_master in [format!("{upstream_remote}/master"), format!("origin/master")] {
+        if rev_exists(&upstream_master, git_dir)? {
+            return Ok(upstream_master);
+        }
     }
 
-    // We could implement smarter logic here in the future.
-    Ok("origin/master".into())
+    Err(format!("Cannot find any suitable upstream master branch"))
+}
+
+pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> {
+    let updated_master = updated_master_branch(git_dir)?;
+    let mut git = Command::new("git");
+    if let Some(git_dir) = git_dir {
+        git.current_dir(git_dir);
+    }
+    Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
 }
 
 /// Returns the files that have been modified in the current branch compared to the master branch.
@@ -94,20 +103,13 @@ pub fn get_git_modified_files(
     git_dir: Option<&Path>,
     extensions: &Vec<&str>,
 ) -> Result<Option<Vec<String>>, String> {
-    let Ok(updated_master) = updated_master_branch(git_dir) else {
-        return Ok(None);
-    };
-
-    let git = || {
-        let mut git = Command::new("git");
-        if let Some(git_dir) = git_dir {
-            git.current_dir(git_dir);
-        }
-        git
-    };
+    let merge_base = get_git_merge_base(git_dir)?;
 
-    let merge_base = output_result(git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
-    let files = output_result(git().arg("diff-index").arg("--name-only").arg(merge_base.trim()))?
+    let mut git = Command::new("git");
+    if let Some(git_dir) = git_dir {
+        git.current_dir(git_dir);
+    }
+    let files = output_result(git.args(["diff-index", "--name-only", merge_base.trim()]))?
         .lines()
         .map(|s| s.trim().to_owned())
         .filter(|f| {
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 7ac9416d82cd4fc5e707c9ec3574d22dff6466e
+Subproject c91a693e7977e33a1064b63a5daf5fb689f0165
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 4eb11a3ac85..5c69714bc1e 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -187,16 +187,14 @@ jobs:
     - name: Extract Binaries
       run: |
         DIR=$CARGO_TARGET_DIR/debug
-        rm $DIR/deps/integration-*.d
-        mv $DIR/deps/integration-* $DIR/integration
+        find $DIR/deps/integration-* -executable ! -type d | xargs -I {} mv {} $DIR/integration
         find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
-        rm -rf $CARGO_TARGET_DIR/release
 
     - name: Upload Binaries
-      uses: actions/upload-artifact@v1
+      uses: actions/upload-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
   integration:
     needs: integration_build
@@ -206,22 +204,20 @@ jobs:
       matrix:
         integration:
         - 'rust-lang/cargo'
-        # FIXME: re-enable once fmt_macros is renamed in RLS
-        # - 'rust-lang/rls'
         - 'rust-lang/chalk'
         - 'rust-lang/rustfmt'
         - 'Marwes/combine'
         - 'Geal/nom'
         - 'rust-lang/stdarch'
         - 'serde-rs/serde'
-        # FIXME: chrono currently cannot be compiled with `--all-targets`
-        # - 'chronotope/chrono'
+        - 'chronotope/chrono'
         - 'hyperium/hyper'
         - 'rust-random/rand'
         - 'rust-lang/futures-rs'
         - 'rust-itertools/itertools'
         - 'rust-lang-nursery/failure'
         - 'rust-lang/log'
+        - 'matthiaskrgr/clippy_ci_panic_test'
 
     runs-on: ubuntu-latest
 
@@ -237,12 +233,17 @@ jobs:
     - name: Install toolchain
       run: rustup show active-toolchain
 
+    - name: Set LD_LIBRARY_PATH
+      run: |
+        SYSROOT=$(rustc --print sysroot)
+        echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
+
     # Download
     - name: Download target dir
-      uses: actions/download-artifact@v1
+      uses: actions/download-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
     - name: Make Binaries Executable
       run: chmod +x $CARGO_TARGET_DIR/debug/*
@@ -251,7 +252,7 @@ jobs:
     - name: Test ${{ matrix.integration }}
       run: |
         RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \
-          $CARGO_TARGET_DIR/debug/integration
+          $CARGO_TARGET_DIR/debug/integration --show-output
       env:
         INTEGRATION: ${{ matrix.integration }}
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index b3b6e3b865f..2655d93599e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4680,6 +4680,7 @@ Released 2018-09-13
 
 <!-- lint disable no-unused-definitions -->
 <!-- begin autogenerated links to lint list -->
+[`absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes
@@ -4819,6 +4820,7 @@ Released 2018-09-13
 [`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 [`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
+[`error_impl_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#error_impl_error
 [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 [`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
 [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
@@ -4842,6 +4844,7 @@ Released 2018-09-13
 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
+[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
 [`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
@@ -4865,8 +4868,10 @@ Released 2018-09-13
 [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
 [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_collect
 [`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 [`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
+[`four_forward_slashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#four_forward_slashes
 [`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 [`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
@@ -4937,6 +4942,7 @@ Released 2018-09-13
 [`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
 [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
+[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
 [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
@@ -5092,6 +5098,7 @@ Released 2018-09-13
 [`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
 [`needless_raw_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_strings
 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark
 [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
@@ -5174,6 +5181,7 @@ Released 2018-09-13
 [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 [`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim
 [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
+[`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock
 [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
 [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
@@ -5185,6 +5193,8 @@ Released 2018-09-13
 [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
@@ -5254,6 +5264,7 @@ Released 2018-09-13
 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_lit_chars_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_chars_any
 [`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
@@ -5362,6 +5373,7 @@ Released 2018-09-13
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
+[`unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default
 [`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 [`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
@@ -5462,4 +5474,6 @@ Released 2018-09-13
 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
 [`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments
+[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index f8073dac330..caaad6d1173 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -730,3 +730,24 @@ Whether to allow `r#""#` when `r""` can be used
 * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
 
 
+## `absolute-paths-max-segments`
+The maximum number of segments a path can have before being linted, anything above this will
+be linted.
+
+**Default Value:** `2` (`u64`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
+## `absolute-paths-allowed-crates`
+Which crates to allow absolute paths from
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 4624451cff4..c4ae4f0e2bd 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -51,7 +51,7 @@ pub fn clippy_project_root() -> PathBuf {
     for path in current_dir.ancestors() {
         let result = std::fs::read_to_string(path.join("Cargo.toml"));
         if let Err(err) = &result {
-            if err.kind() == std::io::ErrorKind::NotFound {
+            if err.kind() == io::ErrorKind::NotFound {
                 continue;
             }
         }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index f39bc06e6d7..e64cf2c8749 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -96,8 +96,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
 
         path.push("src");
         fs::create_dir(&path)?;
-        let header = format!("//@compile-flags: --crate-name={lint_name}");
-        write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
+        write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
 
         Ok(())
     }
@@ -113,7 +112,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
         println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
     } else {
         let test_path = format!("tests/ui/{}.rs", lint.name);
-        let test_contents = get_test_file_contents(lint.name, None);
+        let test_contents = get_test_file_contents(lint.name);
         write_file(lint.project_root.join(&test_path), test_contents)?;
 
         println!("Generated test file: `{test_path}`");
@@ -195,23 +194,16 @@ pub(crate) fn get_stabilization_version() -> String {
     parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
 }
 
-fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
-    let mut contents = formatdoc!(
+fn get_test_file_contents(lint_name: &str) -> String {
+    formatdoc!(
         r#"
-        #![allow(unused)]
         #![warn(clippy::{lint_name})]
 
         fn main() {{
             // test code goes here
         }}
     "#
-    );
-
-    if let Some(header) = header_commands {
-        contents = format!("{header}\n{contents}");
-    }
-
-    contents
+    )
 }
 
 fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
new file mode 100644
index 00000000000..04417c4c460
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::{HirId, ItemKind, Node, Path};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of items through absolute paths, like `std::env::current_dir`.
+    ///
+    /// ### Why is this bad?
+    /// Many codebases have their own style when it comes to importing, but one that is seldom used
+    /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you
+    /// should add a `use` statement.
+    ///
+    /// The default maximum segments (2) is pretty strict, you may want to increase this in
+    /// `clippy.toml`.
+    ///
+    /// Note: One exception to this is code from macro expansion - this does not lint such cases, as
+    /// using absolute paths is the proper way of referencing items in one.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = std::f64::consts::PI;
+    /// ```
+    /// Use any of the below instead, or anything else:
+    /// ```rust
+    /// use std::f64;
+    /// use std::f64::consts;
+    /// use std::f64::consts::PI;
+    /// let x = f64::consts::PI;
+    /// let x = consts::PI;
+    /// let x = PI;
+    /// use std::f64::consts as f64_consts;
+    /// let x = f64_consts::PI;
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub ABSOLUTE_PATHS,
+    restriction,
+    "checks for usage of an item without a `use` statement"
+}
+impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
+
+pub struct AbsolutePaths {
+    pub absolute_paths_max_segments: u64,
+    pub absolute_paths_allowed_crates: FxHashSet<String>,
+}
+
+impl LateLintPass<'_> for AbsolutePaths {
+    // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
+    // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
+    // a `Use`
+    #[expect(clippy::cast_possible_truncation)]
+    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
+        let Self {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates,
+        } = self;
+
+        if !path.span.from_expansion()
+            && let Some(node) = cx.tcx.hir().find(hir_id)
+            && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
+            && let [first, rest @ ..] = path.segments
+            // Handle `::std`
+            && let (segment, len) = if first.ident.name == kw::PathRoot {
+                // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1`
+                // is fine here for the same reason
+                (&rest[0], path.segments.len() - 1)
+            } else {
+                (first, path.segments.len())
+            }
+            && len > *absolute_paths_max_segments as usize
+            && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span)
+            && segment_snippet == segment.ident.as_str()
+        {
+            let is_abs_external =
+                matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
+            let is_abs_crate = segment.ident.name == kw::Crate;
+
+            if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str())
+                || is_abs_crate && absolute_paths_allowed_crates.contains("crate")
+            {
+                return;
+            }
+
+            if is_abs_external || is_abs_crate {
+                span_lint(
+                    cx,
+                    ABSOLUTE_PATHS,
+                    path.span,
+                    "consider bringing this path into scope with the `use` keyword",
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 7adcd9ad055..35a04b5e44a 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::last_path_segment;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_from_proc_macro, last_path_segment};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -38,10 +38,11 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
 
-impl LateLintPass<'_> for ArcWithNonSendSync {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        let ty = cx.typeck_results().expr_ty(expr);
-        if is_type_diagnostic_item(cx, ty, sym::Arc)
+impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(expr)
+            && is_type_diagnostic_item(cx, ty, sym::Arc)
             && let ExprKind::Call(func, [arg]) = expr.kind
             && let ExprKind::Path(func_path) = func.kind
             && last_path_segment(&func_path).ident.name == sym::new
@@ -54,6 +55,7 @@ impl LateLintPass<'_> for ArcWithNonSendSync {
             && let Some(sync) = cx.tcx.lang_items().sync_trait()
             && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
             && !(is_send && is_sync)
+            && !is_from_proc_macro(cx, expr)
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 0ac6ef6496a..d34de305f5d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -181,6 +181,14 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
+    /// ### Known problems
+    /// When the expression on the left is a function call, the lint considers the return type to be
+    /// a type alias if it's aliased through a `use` statement
+    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    ///
+    /// This check is also rather primitive. It will only work on primitive types without any
+    /// intermediate references, raw pointers and trait objects may or may not work.
+    ///
     /// ### Example
     /// ```rust
     /// let _ = 2i32 as i32;
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index ae56f38d9ad..86057bb74ee 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -85,11 +85,6 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    // skip cast of fn call that returns type alias
-    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
-        return false;
-    }
-
     // skip cast to non-primitive type
     if_chain! {
         if let ExprKind::Cast(_, cast_to) = expr.kind;
@@ -101,6 +96,11 @@ pub(super) fn check<'tcx>(
         }
     }
 
+    // skip cast of fn call that returns type alias
+    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+        return false;
+    }
+
     if let Some(lit) = get_numeric_literal(cast_expr) {
         let literal_str = &cast_str;
 
@@ -254,14 +254,12 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 // function's declaration snippet is exactly equal to the `Ty`. That way, we can
                 // see whether it's a type alias.
                 //
-                // Will this work for more complex types? Probably not!
+                // FIXME: This won't work if the type is given an alias through `use`, should we
+                // consider this a type alias as well?
                 if !snippet
                     .split("->")
-                    .skip(0)
-                    .map(|s| {
-                        s.trim() == cast_from.to_string()
-                            || s.split("where").any(|ty| ty.trim() == cast_from.to_string())
-                    })
+                    .skip(1)
+                    .map(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
                     .any(|a| a)
                 {
                     return ControlFlow::Break(());
@@ -288,3 +286,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
     })
     .is_some()
 }
+
+fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
+    snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 498d657b31f..d4e0d286334 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -37,6 +37,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+    crate::absolute_paths::ABSOLUTE_PATHS_INFO,
     crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
@@ -155,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::enum_variants::MODULE_INCEPTION_INFO,
     crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
     crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
+    crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
     crate::escape::BOXED_LOCAL_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
@@ -183,6 +185,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
     crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
     crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
+    crate::four_forward_slashes::FOUR_FORWARD_SLASHES_INFO,
     crate::from_over_into::FROM_OVER_INTO_INFO,
     crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
     crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
@@ -305,6 +308,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
     crate::matches::MATCH_WILD_ERR_ARM_INFO,
     crate::matches::NEEDLESS_MATCH_INFO,
+    crate::matches::REDUNDANT_GUARDS_INFO,
     crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
     crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
     crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
@@ -333,11 +337,13 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::EXPECT_USED_INFO,
     crate::methods::EXTEND_WITH_DRAIN_INFO,
     crate::methods::FILETYPE_IS_FILE_INFO,
+    crate::methods::FILTER_MAP_BOOL_THEN_INFO,
     crate::methods::FILTER_MAP_IDENTITY_INFO,
     crate::methods::FILTER_MAP_NEXT_INFO,
     crate::methods::FILTER_NEXT_INFO,
     crate::methods::FLAT_MAP_IDENTITY_INFO,
     crate::methods::FLAT_MAP_OPTION_INFO,
+    crate::methods::FORMAT_COLLECT_INFO,
     crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
     crate::methods::GET_FIRST_INFO,
     crate::methods::GET_LAST_WITH_LEN_INFO,
@@ -358,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
     crate::methods::ITER_OVEREAGER_CLONED_INFO,
     crate::methods::ITER_SKIP_NEXT_INFO,
+    crate::methods::ITER_SKIP_ZERO_INFO,
     crate::methods::ITER_WITH_DRAIN_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
@@ -391,6 +398,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::OR_THEN_UNWRAP_INFO,
     crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
     crate::methods::RANGE_ZIP_WITH_LEN_INFO,
+    crate::methods::READONLY_WRITE_LOCK_INFO,
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
@@ -403,6 +411,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::SKIP_WHILE_NEXT_INFO,
     crate::methods::STABLE_SORT_PRIMITIVE_INFO,
     crate::methods::STRING_EXTEND_CHARS_INFO,
+    crate::methods::STRING_LIT_CHARS_ANY_INFO,
     crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
     crate::methods::SUSPICIOUS_MAP_INFO,
     crate::methods::SUSPICIOUS_SPLITN_INFO,
@@ -418,7 +427,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
-    crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
+    crate::methods::UNWRAP_OR_DEFAULT_INFO,
     crate::methods::UNWRAP_USED_INFO,
     crate::methods::USELESS_ASREF_INFO,
     crate::methods::VEC_RESIZE_TO_ZERO_INFO,
@@ -555,6 +564,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
     crate::redundant_else::REDUNDANT_ELSE_INFO,
     crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+    crate::redundant_locals::REDUNDANT_LOCALS_INFO,
     crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
     crate::redundant_slicing::DEREF_BY_SLICING_INFO,
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
@@ -568,6 +578,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
     crate::returns::LET_AND_RETURN_INFO,
     crate::returns::NEEDLESS_RETURN_INFO,
+    crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO,
     crate::same_name_method::SAME_NAME_METHOD_INFO,
     crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
     crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 8a9d978a106..a5ec979ccd9 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,21 +3,23 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
+use clippy_utils::ty::{is_copy, peel_mid_ty_refs};
 use clippy_utils::{
-    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
+    expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
 };
 
+use hir::def::DefKind;
+use hir::MatchSource;
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
-    ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
-    TraitItemKind, TyKind, UnOp,
+    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind,
+    Path, QPath, TyKind, UnOp,
 };
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -25,8 +27,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
-    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamEnv, ParamTy, ProjectionPredicate, Ty,
+    TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
@@ -163,7 +165,7 @@ impl_lint_pass!(Dereferencing<'_> => [
 
 #[derive(Default)]
 pub struct Dereferencing<'tcx> {
-    state: Option<(State, StateData)>,
+    state: Option<(State, StateData<'tcx>)>,
 
     // While parsing a `deref` method call in ufcs form, the path to the function is itself an
     // expression. This is to store the id of that expression so it can be skipped when
@@ -203,29 +205,28 @@ impl<'tcx> Dereferencing<'tcx> {
 }
 
 #[derive(Debug)]
-struct StateData {
+struct StateData<'tcx> {
     /// Span of the top level expression
     span: Span,
     hir_id: HirId,
-    position: Position,
+    adjusted_ty: Ty<'tcx>,
 }
 
-#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
-    snip_expr: Option<HirId>,
+    stability: TyCoercionStability,
+    for_field_access: Option<Symbol>,
 }
 
-#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
         // The number of calls in a sequence which changed the referenced type
         ty_changed_count: usize,
-        is_final_ufcs: bool,
+        is_ufcs: bool,
         /// The required mutability
-        target_mut: Mutability,
+        mutbl: Mutability,
     },
     DerefedBorrow(DerefedBorrow),
     ExplicitDeref {
@@ -244,7 +245,7 @@ enum State {
 
 // A reference operation considered by this lint pass
 enum RefOp {
-    Method(Mutability),
+    Method { mutbl: Mutability, is_ufcs: bool },
     Deref,
     AddrOf(Mutability),
 }
@@ -294,48 +295,115 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
         match (self.state.take(), kind) {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
-                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
-                match kind {
-                    RefOp::Deref => {
+                let use_cx = expr_use_ctxt(cx, expr);
+                let adjusted_ty = match &use_cx {
+                    Some(use_cx) => match use_cx.adjustments {
+                        [.., a] => a.target,
+                        _ => expr_ty,
+                    },
+                    _ => typeck.expr_ty_adjusted(expr),
+                };
+
+                match (use_cx, kind) {
+                    (Some(use_cx), RefOp::Deref) => {
                         let sub_ty = typeck.expr_ty(sub_expr);
-                        if let Position::FieldAccess {
-                            name,
-                            of_union: false,
-                        } = position
-                            && !ty_contains_field(sub_ty, name)
+                        if let ExprUseNode::FieldAccess(name) = use_cx.node
+                            && adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union())
+                            && !ty_contains_field(sub_ty, name.name)
                         {
                             self.state = Some((
-                                State::ExplicitDerefField { name },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                State::ExplicitDerefField { name: name.name },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
-                        } else if position.is_deref_stable() && sub_ty.is_ref() {
+                        } else if sub_ty.is_ref()
+                            // Linting method receivers would require verifying that name lookup
+                            // would resolve the same way. This is complicated by trait methods.
+                            && !use_cx.node.is_recv()
+                            && let Some(ty) = use_cx.node.defined_ty(cx)
+                            && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable()
+                        {
                             self.state = Some((
                                 State::ExplicitDeref { mutability: None },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
                         }
                     },
-                    RefOp::Method(target_mut)
+                    (_, RefOp::Method { mutbl, is_ufcs })
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
-                            && position.lint_explicit_deref() =>
+                            // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
+                            && (is_ufcs || !in_postfix_position(cx, expr)) =>
                     {
                         let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
                         self.state = Some((
                             State::DerefMethod {
                                 ty_changed_count,
-                                is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                                target_mut,
+                                is_ufcs,
+                                mutbl,
                             },
                             StateData {
                                 span: expr.span,
                                 hir_id: expr.hir_id,
-                                position,
+                                adjusted_ty,
                             },
                         ));
                     },
-                    RefOp::AddrOf(mutability) => {
+                    (Some(use_cx), RefOp::AddrOf(mutability)) => {
+                        let defined_ty = use_cx.node.defined_ty(cx);
+
+                        // Check needless_borrow for generic arguments.
+                        if !use_cx.is_ty_unified
+                            && let Some(DefinedTy::Mir(ty)) = defined_ty
+                            && let ty::Param(ty) = *ty.value.skip_binder().kind()
+                            && let Some((hir_id, fn_id, i)) = match use_cx.node {
+                                ExprUseNode::MethodArg(_, _, 0) => None,
+                                ExprUseNode::MethodArg(hir_id, None, i) => {
+                                    typeck.type_dependent_def_id(hir_id).map(|id| (hir_id, id, i))
+                                },
+                                ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i)
+                                if !path_has_args(p) => match typeck.qpath_res(p, hir_id) {
+                                    Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => {
+                                        Some((hir_id, id, i))
+                                    },
+                                    _ => None,
+                                },
+                                _ => None,
+                            } && let count = needless_borrow_generic_arg_count(
+                                cx,
+                                &mut self.possible_borrowers,
+                                fn_id,
+                                typeck.node_args(hir_id),
+                                i,
+                                ty,
+                                expr,
+                                &self.msrv,
+                            ) && count != 0
+                        {
+                            self.state = Some((
+                                State::DerefedBorrow(DerefedBorrow {
+                                    count: count - 1,
+                                    msg: "the borrowed expression implements the required traits",
+                                    stability: TyCoercionStability::None,
+                                    for_field_access: None,
+                                }),
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+                                },
+                            ));
+                            return;
+                        }
+
                         // Find the number of times the borrow is auto-derefed.
-                        let mut iter = adjustments.iter();
+                        let mut iter = use_cx.adjustments.iter();
                         let mut deref_count = 0usize;
                         let next_adjust = loop {
                             match iter.next() {
@@ -352,6 +420,58 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             };
                         };
 
+                        let stability = defined_ty.map_or(TyCoercionStability::None, |ty| {
+                            TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
+                        });
+                        let can_auto_borrow = match use_cx.node {
+                            ExprUseNode::Callee => true,
+                            ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
+                            ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
+                                // Check for calls to trait methods where the trait is implemented
+                                // on a reference.
+                                // Two cases need to be handled:
+                                // * `self` methods on `&T` will never have auto-borrow
+                                // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                                //   priority.
+                                if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
+                                    && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                                    && let arg_ty
+                                        = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
+                                    && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+                                    && let args = cx
+                                        .typeck_results()
+                                        .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
+                                    && let impl_ty = if cx.tcx.fn_sig(fn_id)
+                                        .instantiate_identity()
+                                        .skip_binder()
+                                        .inputs()[0].is_ref()
+                                    {
+                                        // Trait methods taking `&self`
+                                        sub_ty
+                                    } else {
+                                        // Trait methods taking `self`
+                                        arg_ty
+                                    } && impl_ty.is_ref()
+                                    && cx.tcx.infer_ctxt().build()
+                                        .type_implements_trait(
+                                            trait_id,
+                                            [impl_ty.into()].into_iter().chain(args.iter().copied()),
+                                            cx.param_env,
+                                        )
+                                        .must_apply_modulo_regions()
+                                {
+                                    false
+                                } else {
+                                    true
+                                }
+                            },
+                            _ => false,
+                        };
+
+                        let deref_msg =
+                            "this expression creates a reference which is immediately dereferenced by the compiler";
+                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+
                         // Determine the required number of references before any can be removed. In all cases the
                         // reference made by the current expression will be removed. After that there are four cases to
                         // handle.
@@ -374,26 +494,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         //        };
                         //    }
                         //    ```
-                        let deref_msg =
-                            "this expression creates a reference which is immediately dereferenced by the compiler";
-                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
-                        let impl_msg = "the borrowed expression implements the required traits";
-
-                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
-                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
-                        } else if let Position::ImplArg(hir_id) = position {
-                            (0, impl_msg, Some(hir_id))
-                        } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
-                            next_adjust.map(|a| &a.kind)
+                        let (required_refs, msg) = if can_auto_borrow {
+                            (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        } else if let Some(&Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
+                                ..
+                            }) = next_adjust
+                            && matches!(mutability, AutoBorrowMutability::Mut { .. })
+                            && !stability.is_reborrow_stable()
                         {
-                            if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
-                            {
-                                (3, deref_msg, None)
-                            } else {
-                                (2, deref_msg, None)
-                            }
+                            (3, deref_msg)
                         } else {
-                            (2, deref_msg, None)
+                            (2, deref_msg)
                         };
 
                         if deref_count >= required_refs {
@@ -403,15 +515,19 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                     // can't be removed without breaking the code. See earlier comment.
                                     count: deref_count - required_refs,
                                     msg,
-                                    snip_expr,
+                                    stability,
+                                    for_field_access: match use_cx.node {
+                                        ExprUseNode::FieldAccess(name) => Some(name.name),
+                                        _ => None,
+                                    },
                                 }),
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
-                        } else if position.is_deref_stable()
+                        } else if stability.is_deref_stable()
                             // Auto-deref doesn't combine with other adjustments
                             && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                             && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
@@ -421,24 +537,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
                         }
                     },
-                    RefOp::Method(..) => (),
+                    (None, _) | (_, RefOp::Method { .. }) => (),
                 }
             },
             (
                 Some((
                     State::DerefMethod {
-                        target_mut,
+                        mutbl,
                         ty_changed_count,
                         ..
                     },
                     data,
                 )),
-                RefOp::Method(_),
+                RefOp::Method { is_ufcs, .. },
             ) => {
                 self.state = Some((
                     State::DerefMethod {
@@ -447,8 +563,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         } else {
                             ty_changed_count + 1
                         },
-                        is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                        target_mut,
+                        is_ufcs,
+                        mutbl,
                     },
                     data,
                 ));
@@ -463,33 +579,44 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 ));
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if position.is_deref_stable() {
+                if stability.is_deref_stable() {
                     self.state = Some((
                         State::Borrow { mutability },
                         StateData {
                             span: expr.span,
                             hir_id: expr.hir_id,
-                            position,
+                            adjusted_ty,
                         },
                     ));
                 }
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
+                let for_field_access = state.for_field_access;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if let Position::FieldAccess{name, ..} = position
+                if let Some(name) = for_field_access
                     && !ty_contains_field(typeck.expr_ty(sub_expr), name)
                 {
                     self.state = Some((
                         State::ExplicitDerefField { name },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
-                } else if position.is_deref_stable() {
+                } else if stability.is_deref_stable() {
                     self.state = Some((
                         State::ExplicitDeref { mutability: None },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
                 }
             },
@@ -611,8 +738,8 @@ fn try_parse_ref_op<'tcx>(
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
-    let (def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+    let (is_ufcs, def_id, arg) = match expr.kind {
+        ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(path),
@@ -620,7 +747,7 @@ fn try_parse_ref_op<'tcx>(
                 ..
             },
             [arg],
-        ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+        ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
             return Some((RefOp::Deref, sub_expr));
         },
@@ -628,9 +755,21 @@ fn try_parse_ref_op<'tcx>(
         _ => return None,
     };
     if tcx.is_diagnostic_item(sym::deref_method, def_id) {
-        Some((RefOp::Method(Mutability::Not), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Not,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
-        Some((RefOp::Method(Mutability::Mut), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Mut,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else {
         None
     }
@@ -649,420 +788,164 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
     }
 }
 
-/// The position of an expression relative to it's parent.
-#[derive(Clone, Copy, Debug)]
-enum Position {
-    MethodReceiver,
-    /// The method is defined on a reference type. e.g. `impl Foo for &T`
-    MethodReceiverRefImpl,
-    Callee,
-    ImplArg(HirId),
-    FieldAccess {
-        name: Symbol,
-        of_union: bool,
-    }, // union fields cannot be auto borrowed
-    Postfix,
-    Deref,
-    /// Any other location which will trigger auto-deref to a specific time.
-    /// Contains the precedence of the parent expression and whether the target type is sized.
-    DerefStable(i8, bool),
-    /// Any other location which will trigger auto-reborrowing.
-    /// Contains the precedence of the parent expression.
-    ReborrowStable(i8),
-    /// Contains the precedence of the parent expression.
-    Other(i8),
-}
-impl Position {
-    fn is_deref_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..))
+fn path_has_args(p: &QPath<'_>) -> bool {
+    match *p {
+        QPath::Resolved(_, Path { segments: [.., s], .. }) | QPath::TypeRelative(_, s) => s.args.is_some(),
+        _ => false,
     }
+}
 
-    fn is_reborrow_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
+fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, e)
+        && parent.span.ctxt() == e.span.ctxt()
+    {
+        match parent.kind {
+            ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _)
+                if child.hir_id == e.hir_id => true,
+            ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true,
+            _ => false,
+        }
+    } else {
+        false
     }
+}
 
-    fn can_auto_borrow(self) -> bool {
-        matches!(
-            self,
-            Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
-        )
+#[derive(Clone, Copy)]
+enum TyCoercionStability {
+    Deref,
+    Reborrow,
+    None,
+}
+impl TyCoercionStability {
+    fn is_deref_stable(self) -> bool {
+        matches!(self, Self::Deref)
     }
 
-    fn lint_explicit_deref(self) -> bool {
-        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
+    fn is_reborrow_stable(self) -> bool {
+        matches!(self, Self::Deref | Self::Reborrow)
     }
 
-    fn precedence(self) -> i8 {
-        match self {
-            Self::MethodReceiver
-            | Self::MethodReceiverRefImpl
-            | Self::Callee
-            | Self::FieldAccess { .. }
-            | Self::Postfix => PREC_POSTFIX,
-            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
-            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
+    fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self {
+        match ty {
+            DefinedTy::Hir(ty) => Self::for_hir_ty(ty),
+            DefinedTy::Mir(ty) => Self::for_mir_ty(
+                cx.tcx,
+                ty.param_env,
+                cx.tcx.erase_late_bound_regions(ty.value),
+                for_return,
+            ),
         }
     }
-}
-
-/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
-/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
-/// locations as those follow different rules.
-#[expect(clippy::too_many_lines)]
-fn walk_parents<'tcx>(
-    cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    e: &'tcx Expr<'_>,
-    msrv: &Msrv,
-) -> (Position, &'tcx [Adjustment<'tcx>]) {
-    let mut adjustments = [].as_slice();
-    let mut precedence = 0i8;
-    let ctxt = e.span.ctxt();
-    let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| {
-        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
-        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
-            adjustments = cx.typeck_results().expr_adjustments(e);
-        }
-        match parent {
-            Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
-                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
-            },
-            Node::Item(&Item {
-                kind: ItemKind::Static(..) | ItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let ty = cx.tcx.type_of(owner_id.def_id).instantiate_identity();
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
-            },
 
-            Node::Item(&Item {
-                kind: ItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let output = cx
-                    .tcx
-                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).instantiate_identity().output());
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
-            },
-
-            Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
-                Some(Expr {
-                    hir_id,
-                    kind: ExprKind::Struct(path, ..),
-                    ..
-                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
-                    .and_then(|(adt, variant)| {
-                        variant
-                            .fields
-                            .iter()
-                            .find(|f| f.name == field.ident.name)
-                            .map(|f| (adt, f))
-                    })
-                    .map(|(adt, field_def)| {
-                        ty_auto_deref_stability(
-                            cx.tcx,
-                            // Use the param_env of the target type.
-                            cx.tcx.param_env(adt.did()),
-                            cx.tcx.type_of(field_def.did).instantiate_identity(),
-                            precedence,
-                        )
-                        .position_for_arg()
-                    }),
-                _ => None,
-            },
+    // Checks the stability of type coercions when assigned to a binding with the given explicit type.
+    //
+    // e.g.
+    // let x = Box::new(Box::new(0u32));
+    // let y1: &Box<_> = x.deref();
+    // let y2: &Box<_> = &x;
+    //
+    // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
+    // switching to auto-dereferencing.
+    fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
+        let TyKind::Ref(_, ty) = &ty.kind else {
+            return Self::None;
+        };
+        let mut ty = ty;
 
-            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
-                ExprKind::Ret(_) => {
-                    let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
-                    Some(
-                        if let Node::Expr(
-                            closure_expr @ Expr {
-                                kind: ExprKind::Closure(closure),
-                                ..
-                            },
-                        ) = cx.tcx.hir().get_by_def_id(owner_id)
-                        {
-                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
-                        } else {
-                            let output = cx
-                                .tcx
-                                .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).instantiate_identity().output());
-                            ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
-                        },
-                    )
-                },
-                ExprKind::Closure(closure) => Some(closure_result_position(
-                    cx,
-                    closure,
-                    cx.typeck_results().expr_ty(parent),
-                    precedence,
-                )),
-                ExprKind::Call(func, _) if func.hir_id == child_id => {
-                    (child_id == e.hir_id).then_some(Position::Callee)
+        loop {
+            break match ty.ty.kind {
+                TyKind::Ref(_, ref ref_ty) => {
+                    ty = ref_ty;
+                    continue;
                 },
-                ExprKind::Call(func, args) => args
-                    .iter()
-                    .position(|arg| arg.hir_id == child_id)
-                    .zip(expr_sig(cx, func))
-                    .and_then(|(i, sig)| {
-                        sig.input_with_hir(i).map(|(hir_ty, ty)| {
-                            match hir_ty {
-                                // Type inference for closures can depend on how they're called. Only go by the explicit
-                                // types here.
-                                Some(hir_ty) => {
-                                    binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
-                                },
-                                None => {
-                                    // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                                    // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
-                                    if e.hir_id == child_id
-                                        && !call_is_qualified(func)
-                                        && let ty::Param(param_ty) = ty.skip_binder().kind()
-                                    {
-                                        needless_borrow_impl_arg_position(
-                                            cx,
-                                            possible_borrowers,
-                                            parent,
-                                            i,
-                                            *param_ty,
-                                            e,
-                                            precedence,
-                                            msrv,
-                                        )
-                                    } else {
-                                        ty_auto_deref_stability(
-                                            cx.tcx,
-                                            // Use the param_env of the target function.
-                                            sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
-                                            cx.tcx.erase_late_bound_regions(ty),
-                                            precedence
-                                        ).position_for_arg()
-                                    }
-                                },
-                            }
+                TyKind::Path(
+                    QPath::TypeRelative(_, path)
+                    | QPath::Resolved(
+                        _,
+                        Path {
+                            segments: [.., path], ..
+                        },
+                    ),
+                ) => {
+                    if let Some(args) = path.args
+                        && args.args.iter().any(|arg| match arg {
+                            hir::GenericArg::Infer(_) => true,
+                            hir::GenericArg::Type(ty) => ty_contains_infer(ty),
+                            _ => false,
                         })
-                    }),
-                ExprKind::MethodCall(method, receiver, args, _) => {
-                    let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    if receiver.hir_id == child_id {
-                        // Check for calls to trait methods where the trait is implemented on a reference.
-                        // Two cases need to be handled:
-                        // * `self` methods on `&T` will never have auto-borrow
-                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                        //   priority.
-                        if e.hir_id != child_id {
-                            return Some(Position::ReborrowStable(precedence))
-                        } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
-                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
-                            && let subs = cx
-                                .typeck_results()
-                                .node_args_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
-                            && let impl_ty = if cx.tcx.fn_sig(fn_id)
-                                .instantiate_identity()
-                                .skip_binder()
-                                .inputs()[0].is_ref()
-                            {
-                                // Trait methods taking `&self`
-                                sub_ty
-                            } else {
-                                // Trait methods taking `self`
-                                arg_ty
-                            } && impl_ty.is_ref()
-                            && let infcx = cx.tcx.infer_ctxt().build()
-                            && infcx
-                                .type_implements_trait(
-                                    trait_id,
-                                    [impl_ty.into()].into_iter().chain(subs.iter().copied()),
-                                    cx.param_env,
-                                )
-                                .must_apply_modulo_regions()
-                        {
-                            return Some(Position::MethodReceiverRefImpl)
-                        }
-                        return Some(Position::MethodReceiver);
+                    {
+                        Self::Reborrow
+                    } else {
+                        Self::Deref
                     }
-                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        let ty = cx.tcx.fn_sig(fn_id).instantiate_identity().input(i + 1);
-                        // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                        // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
-                        if e.hir_id == child_id
-                            && method.args.is_none()
-                            && let ty::Param(param_ty) = ty.skip_binder().kind()
-                        {
-                            needless_borrow_impl_arg_position(
-                                cx,
-                                possible_borrowers,
-                                parent,
-                                i + 1,
-                                *param_ty,
-                                e,
-                                precedence,
-                                msrv,
-                            )
-                        } else {
-                            ty_auto_deref_stability(
-                                cx.tcx,
-                                // Use the param_env of the target function.
-                                cx.tcx.param_env(fn_id),
-                                cx.tcx.erase_late_bound_regions(ty),
-                                precedence,
-                            )
-                            .position_for_arg()
-                        }
-                    })
-                },
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
-                    name: name.name,
-                    of_union: is_union(cx.typeck_results(), child),
-                }),
-                ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
-                ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
-                | ExprKind::Index(child, _)
-                    if child.hir_id == e.hir_id =>
-                {
-                    Some(Position::Postfix)
-                },
-                _ if child_id == e.hir_id => {
-                    precedence = parent.precedence().order();
-                    None
                 },
-                _ => None,
-            },
-            _ => None,
+                TyKind::Slice(_)
+                | TyKind::Array(..)
+                | TyKind::Ptr(_)
+                | TyKind::BareFn(_)
+                | TyKind::Never
+                | TyKind::Tup(_)
+                | TyKind::Path(_) => Self::Deref,
+                TyKind::OpaqueDef(..)
+                | TyKind::Infer
+                | TyKind::Typeof(..)
+                | TyKind::TraitObject(..)
+                | TyKind::Err(_) => Self::Reborrow,
+            };
         }
-    })
-    .unwrap_or(Position::Other(precedence));
-    (position, adjustments)
-}
-
-fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
-    typeck
-        .expr_ty_adjusted(path_expr)
-        .ty_adt_def()
-        .map_or(false, rustc_middle::ty::AdtDef::is_union)
-}
-
-fn closure_result_position<'tcx>(
-    cx: &LateContext<'tcx>,
-    closure: &'tcx Closure<'_>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> Position {
-    match closure.fn_decl.output {
-        FnRetTy::Return(hir_ty) => {
-            if let Some(sig) = ty_sig(cx, ty)
-                && let Some(output) = sig.output()
-            {
-                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
-            } else {
-                Position::Other(precedence)
-            }
-        },
-        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
     }
-}
 
-// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
-//
-// e.g.
-// let x = Box::new(Box::new(0u32));
-// let y1: &Box<_> = x.deref();
-// let y2: &Box<_> = &x;
-//
-// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
-// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: &'tcx hir::Ty<'_>,
-    precedence: i8,
-    binder_args: &'tcx List<BoundVariableKind>,
-) -> Position {
-    let TyKind::Ref(_, ty) = &ty.kind else {
-        return Position::Other(precedence);
-    };
-    let mut ty = ty;
+    fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self {
+        let ty::Ref(_, mut ty, _) = *ty.kind() else {
+            return Self::None;
+        };
 
-    loop {
-        break match ty.ty.kind {
-            TyKind::Ref(_, ref ref_ty) => {
-                ty = ref_ty;
-                continue;
-            },
-            TyKind::Path(
-                QPath::TypeRelative(_, path)
-                | QPath::Resolved(
-                    _,
-                    Path {
-                        segments: [.., path], ..
-                    },
-                ),
-            ) => {
-                if let Some(args) = path.args
-                    && args.args.iter().any(|arg| match arg {
-                        GenericArg::Infer(_) => true,
-                        GenericArg::Type(ty) => ty_contains_infer(ty),
-                        _ => false,
-                    })
+        ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+        loop {
+            break match *ty.kind() {
+                ty::Ref(_, ref_ty, _) => {
+                    ty = ref_ty;
+                    continue;
+                },
+                ty::Param(_) if for_return => Self::Deref,
+                ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"),
+                ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
+                ty::Infer(_)
+                | ty::Error(_)
+                | ty::Bound(..)
+                | ty::Alias(ty::Opaque, ..)
+                | ty::Placeholder(_)
+                | ty::Dynamic(..)
+                | ty::Param(_) => Self::Reborrow,
+                ty::Adt(_, args)
+                    if ty.has_placeholders()
+                        || ty.has_opaque_types()
+                        || (!for_return && args.has_non_region_param()) =>
                 {
-                    Position::ReborrowStable(precedence)
-                } else {
-                    Position::DerefStable(
-                        precedence,
-                        cx.tcx
-                            .erase_late_bound_regions(Binder::bind_with_vars(
-                                cx.typeck_results().node_type(ty.ty.hir_id),
-                                binder_args,
-                            ))
-                            .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-                    )
-                }
-            },
-            TyKind::Slice(_) => Position::DerefStable(precedence, false),
-            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
-            TyKind::Never
-            | TyKind::Tup(_)
-            | TyKind::Path(_) => Position::DerefStable(
-                precedence,
-                cx.tcx
-                    .erase_late_bound_regions(Binder::bind_with_vars(
-                        cx.typeck_results().node_type(ty.ty.hir_id),
-                        binder_args,
-                    ))
-                    .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-            ),
-            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
-                Position::ReborrowStable(precedence)
-            },
-        };
+                    Self::Reborrow
+                },
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Array(..)
+                | ty::Float(_)
+                | ty::RawPtr(..)
+                | ty::FnPtr(_)
+                | ty::Str
+                | ty::Slice(..)
+                | ty::Adt(..)
+                | ty::Foreign(_)
+                | ty::FnDef(..)
+                | ty::Generator(..)
+                | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
+                | ty::Closure(..)
+                | ty::Never
+                | ty::Tuple(_)
+                | ty::Alias(ty::Projection, _) => Self::Deref,
+            };
+        }
     }
 }
 
@@ -1084,10 +967,10 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
             }
         }
 
-        fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
-            if self.0 || matches!(arg, GenericArg::Infer(_)) {
+        fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
+            if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
                 self.0 = true;
-            } else if let GenericArg::Type(ty) = arg {
+            } else if let hir::GenericArg::Type(ty) = arg {
                 self.visit_ty(ty);
             }
         }
@@ -1097,51 +980,29 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     v.0
 }
 
-fn call_is_qualified(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Path(path) = &expr.kind {
-        match path {
-            QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
-            QPath::TypeRelative(_, segment) => segment.args.is_some(),
-            QPath::LangItem(..) => false,
-        }
-    } else {
-        false
-    }
-}
-
-// Checks whether:
-// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
-// * `e`'s type implements `Trait` and is copyable
-// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
-//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
-// be moved, but it cannot be.
-#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
-fn needless_borrow_impl_arg_position<'tcx>(
+/// Checks for the number of borrow expressions which can be removed from the given expression
+/// where the expression is used as an argument to a function expecting a generic type.
+///
+/// The following constraints will be checked:
+/// * The borrowed expression meets all the generic type's constraints.
+/// * The generic type appears only once in the functions signature.
+/// * The borrowed value will not be moved if it is used later in the function.
+#[expect(clippy::too_many_arguments)]
+fn needless_borrow_generic_arg_count<'tcx>(
     cx: &LateContext<'tcx>,
     possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    parent: &Expr<'tcx>,
+    fn_id: DefId,
+    callee_args: &'tcx List<GenericArg<'tcx>>,
     arg_index: usize,
     param_ty: ParamTy,
     mut expr: &Expr<'tcx>,
-    precedence: i8,
     msrv: &Msrv,
-) -> Position {
+) -> usize {
     let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
 
-    let Some(callee_def_id) = fn_def_id(cx, parent) else {
-        return Position::Other(precedence);
-    };
-    let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
-    let args_with_expr_ty = cx
-        .typeck_results()
-        .node_args(if let ExprKind::Call(callee, _) = parent.kind {
-            callee.hir_id
-        } else {
-            parent.hir_id
-        });
-
-    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+    let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
+    let predicates = cx.tcx.param_env(fn_id).caller_bounds();
     let projection_predicates = predicates
         .iter()
         .filter_map(|predicate| {
@@ -1176,7 +1037,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
                 || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
         })
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
     // See:
@@ -1184,14 +1045,14 @@ fn needless_borrow_impl_arg_position<'tcx>(
     // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
     if projection_predicates
         .iter()
-        .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
+        .any(|projection_predicate| is_mixed_projection_predicate(cx, fn_id, projection_predicate))
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
     // `args_with_referent_ty` can be constructed outside of `check_referent` because the same
     // elements are modified each time `check_referent` is called.
-    let mut args_with_referent_ty = args_with_expr_ty.to_vec();
+    let mut args_with_referent_ty = callee_args.to_vec();
 
     let mut check_reference_and_referent = |reference, referent| {
         let referent_ty = cx.typeck_results().expr_ty(referent);
@@ -1238,20 +1099,15 @@ fn needless_borrow_impl_arg_position<'tcx>(
         })
     };
 
-    let mut needless_borrow = false;
+    let mut count = 0;
     while let ExprKind::AddrOf(_, _, referent) = expr.kind {
         if !check_reference_and_referent(expr, referent) {
             break;
         }
         expr = referent;
-        needless_borrow = true;
-    }
-
-    if needless_borrow {
-        Position::ImplArg(expr.hir_id)
-    } else {
-        Position::Other(precedence)
+        count += 1;
     }
+    count
 }
 
 fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
@@ -1392,93 +1248,6 @@ fn replace_types<'tcx>(
     true
 }
 
-struct TyPosition<'tcx> {
-    position: Position,
-    ty: Option<Ty<'tcx>>,
-}
-impl From<Position> for TyPosition<'_> {
-    fn from(position: Position) -> Self {
-        Self { position, ty: None }
-    }
-}
-impl<'tcx> TyPosition<'tcx> {
-    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
-        Self {
-            position: Position::ReborrowStable(precedence),
-            ty: Some(ty),
-        }
-    }
-    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
-        match (self.position, self.ty) {
-            (Position::ReborrowStable(precedence), Some(ty)) => {
-                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
-            },
-            (position, _) => position,
-        }
-    }
-    fn position_for_arg(self) -> Position {
-        self.position
-    }
-}
-
-// Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> TyPosition<'tcx> {
-    let ty::Ref(_, mut ty, _) = *ty.kind() else {
-        return Position::Other(precedence).into();
-    };
-
-    ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
-
-    loop {
-        break match *ty.kind() {
-            ty::Ref(_, ref_ty, _) => {
-                ty = ref_ty;
-                continue;
-            },
-            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
-            ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
-            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
-                TyPosition::new_deref_stable_for_result(precedence, ty)
-            },
-            ty::Infer(_)
-            | ty::Error(_)
-            | ty::Bound(..)
-            | ty::Alias(ty::Opaque, ..)
-            | ty::Placeholder(_)
-            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
-            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
-                Position::ReborrowStable(precedence).into()
-            },
-            ty::Adt(_, args) if args.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Array(..)
-            | ty::Float(_)
-            | ty::RawPtr(..)
-            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
-            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
-            ty::Adt(..)
-            | ty::Foreign(_)
-            | ty::FnDef(..)
-            | ty::Generator(..)
-            | ty::GeneratorWitness(..)
-            | ty::GeneratorWitnessMIR(..)
-            | ty::Closure(..)
-            | ty::Never
-            | ty::Tuple(_)
-            | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
-        };
-    }
-}
-
 fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
     if let ty::Adt(adt, _) = *ty.kind() {
         adt.is_struct() && adt.all_fields().any(|f| f.name == name)
@@ -1488,12 +1257,12 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
 }
 
 #[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
-fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
+fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData<'tcx>) {
     match state {
         State::DerefMethod {
             ty_changed_count,
-            is_final_ufcs,
-            target_mut,
+            is_ufcs,
+            mutbl,
         } => {
             let mut app = Applicability::MachineApplicable;
             let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -1508,12 +1277,12 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             };
             let addr_of_str = if ty_changed_count < ref_count {
                 // Check if a reborrow from &mut T -> &T is required.
-                if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
                     "&*"
                 } else {
                     ""
                 }
-            } else if target_mut == Mutability::Mut {
+            } else if mutbl == Mutability::Mut {
                 "&mut "
             } else {
                 "&"
@@ -1530,7 +1299,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             */
 
             // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
-            if is_final_ufcs {
+            if is_ufcs {
                 return;
             }
 
@@ -1538,7 +1307,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 cx,
                 EXPLICIT_DEREF_METHODS,
                 data.span,
-                match target_mut {
+                match mutbl {
                     Mutability::Not => "explicit `deref` method call",
                     Mutability::Mut => "explicit `deref_mut` method call",
                 },
@@ -1549,13 +1318,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
         },
         State::DerefedBorrow(state) => {
             let mut app = Applicability::MachineApplicable;
-            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
-            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
+            let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
             span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
-                let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
+                let (precedence, calls_field) = match get_parent_node(cx.tcx, data.hir_id) {
+                    Some(Node::Expr(e)) => match e.kind {
+                        ExprKind::Call(callee, _) if callee.hir_id != data.hir_id => (0, false),
+                        ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
+                        _ => (e.precedence().order(), false),
+                    },
+                    _ => (0, false),
+                };
                 let sugg = if !snip_is_macro
+                    && (calls_field || expr.precedence().order() < precedence)
                     && !has_enclosing_paren(&snip)
-                    && (expr.precedence().order() < data.position.precedence() || calls_field)
                 {
                     format!("({snip})")
                 } else {
@@ -1572,7 +1347,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
+                && ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
@@ -1585,9 +1361,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     Mutability::Not => "&",
                     Mutability::Mut => "&mut ",
                 };
-                (prefix, 0)
+                (prefix, PREC_PREFIX)
             } else {
-                ("", data.position.precedence())
+                ("", 0)
             };
             span_lint_hir_and_then(
                 cx,
@@ -1616,7 +1392,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && data.adjusted_ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 91bc30ab577..e3f2026cfe9 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,4 +1,6 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{
+    span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
+};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 use clippy_utils::{is_lint_allowed, match_def_path, paths};
 use if_chain::if_chain;
@@ -6,15 +8,15 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
-    Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind,
+    UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate,
-    TraitPredicate, Ty, TyCtxt,
+    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
+    ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -205,13 +207,10 @@ declare_lint_pass!(Derive => [
 
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
-            ..
-        }) = item.kind
-        {
+        if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), .. }) = item.kind {
             let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
+            let is_automatically_derived =
+                cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -328,7 +327,12 @@ fn check_ord_partial_ord<'tcx>(
 }
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_copy_clone<'tcx>(
+    cx: &LateContext<'tcx>,
+    item: &Item<'_>,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+) {
     let clone_id = match cx.tcx.lang_items().clone_trait() {
         Some(id) if trait_ref.trait_def_id() == Some(id) => id,
         _ => return,
@@ -427,7 +431,14 @@ struct UnsafeVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
+    fn visit_fn(
+        &mut self,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body_id: BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) {
         if self.has_unsafe {
             return;
         }
@@ -463,7 +474,12 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 }
 
 /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_partial_eq_without_eq<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+) {
     if_chain! {
         if let ty::Adt(adt, args) = ty.kind();
         if cx.tcx.visibility(adt.did()).is_public();
@@ -471,12 +487,12 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
         let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
-        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []);
+        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
         // If all of our fields implement `Eq`, we can implement `Eq` too
         if adt
             .all_fields()
             .map(|f| f.ty(cx.tcx, args))
-            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
+            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]));
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
new file mode 100644
index 00000000000..379af9b2234
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
+use clippy_utils::path_res;
+use clippy_utils::ty::implements_trait;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Visibility;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types named `Error` that implement `Error`.
+    ///
+    /// ### Why is this bad?
+    /// It can become confusing when a codebase has 20 types all named `Error`, requiring either
+    /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This
+    /// hinders comprehension, as it requires you to memorize every variation of importing `Error`
+    /// used across a codebase.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Debug)]
+    /// pub enum Error { ... }
+    ///
+    /// impl std::fmt::Display for Error { ... }
+    ///
+    /// impl std::error::Error for Error { ... }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ERROR_IMPL_ERROR,
+    restriction,
+    "exported types named `Error` that implement `Error`"
+}
+declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
+
+impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
+            return;
+        };
+
+        match item.kind {
+            ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[])
+                && item.ident.name == sym::Error
+                && is_visible_outside_module(cx, item.owner_id.def_id) =>
+            {
+                span_lint(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    item.ident.span,
+                    "exported type alias named `Error` that implements `Error`",
+                );
+            },
+            ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+                && error_def_id == trait_def_id
+                && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
+                && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
+                && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
+                && ident.name == sym::Error
+                && is_visible_outside_module(cx, def_id) =>
+            {
+                span_lint_hir_and_then(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    hir_id,
+                    ident.span,
+                    "exported type named `Error` that implements `Error`",
+                    |diag| {
+                        diag.span_note(item.span, "`Error` was implemented here");
+                    }
+                );
+            }
+            _ => {},
+        }
+    }
+}
+
+/// Do not lint private `Error`s, i.e., ones without any `pub` (minus `pub(self)` of course) and
+/// which aren't reexported
+fn is_visible_outside_module(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    !matches!(
+        cx.tcx.visibility(def_id),
+        Visibility::Restricted(mod_def_id) if cx.tcx.parent_module_from_def_id(def_id).to_def_id() == mod_def_id
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 22e10accd35..8d6fb8438b6 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,19 +1,22 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::ty::type_diagnostic_name;
+use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, Binder, BoundConstness, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
+    GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
+};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,14 +75,18 @@ declare_clippy_lint! {
 declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for EtaReduction {
+    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
+        let body = if let ExprKind::Closure(c) = expr.kind
+            && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+            && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+            && !expr.span.from_expansion()
+        {
+            cx.tcx.hir().body(c.body)
+        } else {
             return;
-        }
-        let body = match expr.kind {
-            ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
-            _ => return,
         };
+
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
                 if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
@@ -99,140 +106,209 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             return;
         }
 
-        let closure_ty = cx.typeck_results().expr_ty(expr);
+        let typeck = cx.typeck_results();
+        let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+            closure_subs.as_closure()
+        } else {
+            return;
+        };
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::Call(callee, args) = body.value.kind;
-            if let ExprKind::Path(_) = callee.kind;
-            if check_inputs(cx, body.params, None, args);
-            let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
-            let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
-                .map_or(callee_ty, |id| cx.tcx.type_of(id).instantiate_identity());
-            if check_sig(cx, closure_ty, call_ty);
-            let args = cx.typeck_results().node_args(callee.hir_id);
-            // This fixes some false positives that I don't entirely understand
-            if args.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
-            // A type param function ref like `T::f` is not 'static, however
-            // it is if cast like `T::f as fn()`. This seems like a rustc bug.
-            if !args.types().any(|t| matches!(t.kind(), ty::Param(_)));
-            let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
-            if let ty::Closure(_, args) = *closure_ty.kind();
-            // Don't lint if this is an inclusive range expression.
-            // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684)
-            if !matches!(higher::Range::hir(body.value), Some(higher::Range {
-                start: Some(_),
-                end: Some(_),
-                limits: rustc_ast::RangeLimits::Closed
-            }));
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                        if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
-                            && let args = cx.tcx.erase_late_bound_regions(args.as_closure().sig()).inputs()
-                            && implements_trait(
-                                   cx,
-                                   callee_ty.peel_refs(),
-                                   fn_mut_id,
-                                   &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
-                               )
-                            && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
-                        {
-                                // Mutable closure is used after current expr; we cannot consume it.
-                                snippet = format!("&mut {snippet}");
-                        }
+        if is_adjusted(cx, body.value) {
+            return;
+        }
 
-                        diag.span_suggestion(
-                            expr.span,
-                            "replace the closure with the function itself",
-                            snippet,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                });
-            }
-        );
+        match body.value.kind {
+            ExprKind::Call(callee, args)
+                if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
+            {
+                let callee_ty = typeck.expr_ty(callee).peel_refs();
+                if matches!(
+                    type_diagnostic_name(cx, callee_ty),
+                    Some(sym::Arc | sym::Rc)
+                ) || !check_inputs(typeck, body.params, None, args) {
+                    return;
+                }
+                let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
+                    callee_ty,
+                    |a| a.target.peel_refs(),
+                );
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
-            if check_inputs(cx, body.params, Some(receiver), args);
-            let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
-            let args = cx.typeck_results().node_args(body.value.hir_id);
-            let call_ty = cx.tcx.type_of(method_def_id).instantiate(cx.tcx, args);
-            if check_sig(cx, closure_ty, call_ty);
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
-                    let name = get_ufcs_type_name(cx, method_def_id, args);
-                    diag.span_suggestion(
+                let sig = match callee_ty_adjusted.kind() {
+                    ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
+                    ty::FnPtr(sig) => sig.skip_binder(),
+                    ty::Closure(_, subs) => cx
+                        .tcx
+                        .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+                        .skip_binder(),
+                    _ => {
+                        if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+                            && let subs = typeck.node_args(body.value.hir_id)
+                            && let output = typeck.expr_ty(body.value)
+                            && let ty::Tuple(tys) = *subs.type_at(1).kind()
+                        {
+                            cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+                        } else {
+                            return;
+                        }
+                    },
+                };
+                if check_sig(cx, closure, sig)
+                    && let generic_args = typeck.node_args(callee.hir_id)
+                    // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+                    // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+                    // in a type which is `'static`.
+                    // For now ignore all callee types which reference a type parameter.
+                    && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE,
                         expr.span,
-                        "replace the closure with the method itself",
-                        format!("{name}::{}", path.ident.name),
-                        Applicability::MachineApplicable,
+                        "redundant closure",
+                        |diag| {
+                            if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                                if let Ok((ClosureKind::FnMut, _))
+                                    = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
+                                        cx.param_env,
+                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                        BoundConstness::NotConst,
+                                        ImplPolarity::Positive,
+                                    ) && path_to_local(callee)
+                                        .map_or(
+                                            false,
+                                            |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
+                                        )
+                                {
+                                    // Mutable closure is used after current expr; we cannot consume it.
+                                    snippet = format!("&mut {snippet}");
+                                }
+                                diag.span_suggestion(
+                                    expr.span,
+                                    "replace the closure with the function itself",
+                                    snippet,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
                     );
-                })
-            }
-        );
+                }
+            },
+            ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+                if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                    && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                        expr.span,
+                        "redundant closure",
+                        |diag| {
+                            let args = typeck.node_args(body.value.hir_id);
+                            let name = get_ufcs_type_name(cx, method_def_id, args);
+                            diag.span_suggestion(
+                                expr.span,
+                                "replace the closure with the method itself",
+                                format!("{}::{}", name, path.ident.name),
+                                Applicability::MachineApplicable,
+                            );
+                        },
+                    );
+                }
+            },
+            _ => (),
+        }
     }
 }
 
 fn check_inputs(
-    cx: &LateContext<'_>,
+    typeck: &TypeckResults<'_>,
     params: &[Param<'_>],
-    receiver: Option<&Expr<'_>>,
-    call_args: &[Expr<'_>],
+    self_arg: Option<&Expr<'_>>,
+    args: &[Expr<'_>],
 ) -> bool {
-    if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
-        return false;
+    params.len() == self_arg.map_or(0, |_| 1) + args.len()
+        && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| {
+            matches!(
+                p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None)
+                if path_to_local_id(arg, id)
+            )
+            // Only allow adjustments which change regions (i.e. re-borrowing).
+            && typeck
+                .expr_adjustments(arg)
+                .last()
+                .map_or(true, |a| a.target == typeck.expr_ty(arg))
+        })
+}
+
+fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
+    call_sig.unsafety == Unsafety::Normal
+        && !has_late_bound_to_non_late_bound_regions(
+            cx.tcx
+                .signature_unclosure(closure.sig(), Unsafety::Normal)
+                .skip_binder(),
+            call_sig,
+        )
+}
+
+/// This walks through both signatures and checks for any time a late-bound region is expected by an
+/// `impl Fn` type, but the target signature does not have a late-bound region in the same position.
+///
+/// This is needed because rustc is unable to late bind early-bound regions in a function signature.
+fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
+    fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
+        matches!(from_region.kind(), RegionKind::ReLateBound(..))
+            && !matches!(to_region.kind(), RegionKind::ReLateBound(..))
     }
-    let binding_modes = cx.typeck_results().pat_binding_modes();
-    let check_inputs = |param: &Param<'_>, arg| {
-        match param.pat.kind {
-            PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
-            _ => return false,
-        }
-        // checks that parameters are not bound as `ref` or `ref mut`
-        if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) {
-            return false;
-        }
 
-        match *cx.typeck_results().expr_adjustments(arg) {
-            [] => true,
-            [
-                Adjustment {
-                    kind: Adjust::Deref(None),
-                    ..
+    fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
+        if from_subs.len() != to_subs.len() {
+            return true;
+        }
+        for (from_arg, to_arg) in to_subs.iter().zip(from_subs) {
+            match (from_arg.unpack(), to_arg.unpack()) {
+                (GenericArgKind::Lifetime(from_region), GenericArgKind::Lifetime(to_region)) => {
+                    if check_region(from_region, to_region) {
+                        return true;
+                    }
                 },
-                Adjustment {
-                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
-                    ..
+                (GenericArgKind::Type(from_ty), GenericArgKind::Type(to_ty)) => {
+                    if check_ty(from_ty, to_ty) {
+                        return true;
+                    }
                 },
-            ] => {
-                // re-borrow with the same mutability is allowed
-                let ty = cx.typeck_results().expr_ty(arg);
-                matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
-            },
-            _ => false,
+                (GenericArgKind::Const(_), GenericArgKind::Const(_)) => (),
+                _ => return true,
+            }
         }
-    };
-    std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
-}
-
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
-    let call_sig = call_ty.fn_sig(cx.tcx);
-    if call_sig.unsafety() == Unsafety::Unsafe {
-        return false;
+        false
     }
-    if !closure_ty.has_late_bound_regions() {
-        return true;
+
+    fn check_ty(from_ty: Ty<'_>, to_ty: Ty<'_>) -> bool {
+        match (from_ty.kind(), to_ty.kind()) {
+            (&ty::Adt(_, from_subs), &ty::Adt(_, to_subs)) => check_subs(from_subs, to_subs),
+            (&ty::Array(from_ty, _), &ty::Array(to_ty, _)) | (&ty::Slice(from_ty), &ty::Slice(to_ty)) => {
+                check_ty(from_ty, to_ty)
+            },
+            (&ty::Ref(from_region, from_ty, _), &ty::Ref(to_region, to_ty, _)) => {
+                check_region(from_region, to_region) || check_ty(from_ty, to_ty)
+            },
+            (&ty::Tuple(from_tys), &ty::Tuple(to_tys)) => {
+                from_tys.len() != to_tys.len()
+                    || from_tys
+                        .iter()
+                        .zip(to_tys)
+                        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
+            },
+            _ => from_ty.has_late_bound_regions(),
+        }
     }
-    let ty::Closure(_, args) = closure_ty.kind() else {
-        return false;
-    };
-    let closure_sig = cx.tcx.signature_unclosure(args.as_closure().sig(), Unsafety::Normal);
-    cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
+
+    assert!(from_sig.inputs_and_output.len() == to_sig.inputs_and_output.len());
+    from_sig
+        .inputs_and_output
+        .iter()
+        .zip(to_sig.inputs_and_output)
+        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
 
 fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args: GenericArgsRef<'tcx>) -> String {
@@ -241,7 +317,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args:
     match assoc_item.container {
         ty::TraitContainer => cx.tcx.def_path_str(def_id),
         ty::ImplContainer => {
-            let ty = cx.tcx.type_of(def_id).skip_binder();
+            let ty = cx.tcx.type_of(def_id).instantiate_identity();
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
                 ty::Array(..)
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
new file mode 100644
index 00000000000..419c7734344
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::Item;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for outer doc comments written with 4 forward slashes (`////`).
+    ///
+    /// ### Why is this bad?
+    /// This is (probably) a typo, and results in it not being a doc comment; just a regular
+    /// comment.
+    ///
+    /// ### Example
+    /// ```rust
+    /// //// My amazing data structure
+    /// pub struct Foo {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// /// My amazing data structure
+    /// pub struct Foo {
+    ///     // ...
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FOUR_FORWARD_SLASHES,
+    suspicious,
+    "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
+}
+declare_lint_pass!(FourForwardSlashes => [FOUR_FORWARD_SLASHES]);
+
+impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if item.span.from_expansion() {
+            return;
+        }
+        let sm = cx.sess().source_map();
+        let mut span = cx
+            .tcx
+            .hir()
+            .attrs(item.hir_id())
+            .iter()
+            .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
+        let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else {
+            return;
+        };
+        let mut bad_comments = vec![];
+        for line in (0..end_line.saturating_sub(1)).rev() {
+            let Some(contents) = file.get_line(line).map(|c| c.trim().to_owned()) else {
+                return;
+            };
+            // Keep searching until we find the next item
+            if !contents.is_empty() && !contents.starts_with("//") && !contents.starts_with("#[") {
+                break;
+            }
+
+            if contents.starts_with("////") && !matches!(contents.chars().nth(4), Some('/' | '!')) {
+                let bounds = file.line_bounds(line);
+                let line_span = Span::with_root_ctxt(bounds.start, bounds.end);
+                span = line_span.to(span);
+                bad_comments.push((line_span, contents));
+            }
+        }
+
+        if !bad_comments.is_empty() {
+            span_lint_and_then(
+                cx,
+                FOUR_FORWARD_SLASHES,
+                span,
+                "this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't",
+                |diag| {
+                    let msg = if bad_comments.len() == 1 {
+                        "make this a doc comment by removing one `/`"
+                    } else {
+                        "turn these into doc comments by removing one `/`"
+                    };
+
+                    diag.multipart_suggestion(
+                        msg,
+                        bad_comments
+                            .into_iter()
+                            // It's a little unfortunate but the span includes the `\n` yet the contents
+                            // do not, so we must add it back. If some codebase uses `\r\n` instead they
+                            // will need normalization but it should be fine
+                            .map(|(span, c)| (span, c.replacen("////", "///", 1) + "\n"))
+                            .collect(),
+                        Applicability::MachineApplicable,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
index e6c42ebb832..3c59b839a39 100644
--- a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::paths::ORD_CMP;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res};
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::EarlyBinder;
@@ -59,6 +60,10 @@ declare_clippy_lint! {
     /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
     /// introduce an error upon refactoring.
     ///
+    /// ### Known issues
+    /// Code that calls the `.into()` method instead will be flagged as incorrect, despite `.into()`
+    /// wrapping it in `Some`.
+    ///
     /// ### Limitations
     /// Will not lint if `Self` and `Rhs` do not have the same type.
     ///
@@ -190,6 +195,11 @@ impl LateLintPass<'_> for IncorrectImpls {
                     &[],
                 )
         {
+            // If the `cmp` call likely needs to be fully qualified in the suggestion
+            // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
+            // access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
+            let mut needs_fully_qualified = false;
+
             if block.stmts.is_empty()
                 && let Some(expr) = block.expr
                 && let ExprKind::Call(
@@ -201,9 +211,8 @@ impl LateLintPass<'_> for IncorrectImpls {
                         [cmp_expr],
                     ) = expr.kind
                 && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
-                && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
-                && cmp_path.ident.name == sym::cmp
-                && let Res::Local(..) = path_res(cx, other_expr)
+                // Fix #11178, allow `Self::cmp(self, ..)` too
+                && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
             {} else {
                 // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
                 // suggestion tons more complex.
@@ -220,14 +229,29 @@ impl LateLintPass<'_> for IncorrectImpls {
                         let [_, other] = body.params else {
                             return;
                         };
+                        let Some(std_or_core) = std_or_core(cx) else {
+                            return;
+                        };
 
-                        let suggs = if let Some(other_ident) = other.pat.simple_ident() {
-                            vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
-                        } else {
-                            vec![
+                        let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
+                            (Some(other_ident), true) => vec![(
+                                block.span,
+                                format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
+                            )],
+                            (Some(other_ident), false) => {
+                                vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
+                            },
+                            (None, true) => vec![
+                                (
+                                    block.span,
+                                    format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
+                                ),
+                                (other.pat.span, "other".to_owned()),
+                            ],
+                            (None, false) => vec![
                                 (block.span, "{ Some(self.cmp(other)) }".to_owned()),
                                 (other.pat.span, "other".to_owned()),
-                            ]
+                            ],
                         };
 
                         diag.multipart_suggestion(
@@ -241,3 +265,31 @@ impl LateLintPass<'_> for IncorrectImpls {
         }
     }
 }
+
+/// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
+fn self_cmp_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    cmp_expr: &'tcx Expr<'tcx>,
+    def_id: LocalDefId,
+    needs_fully_qualified: &mut bool,
+) -> bool {
+    match cmp_expr.kind {
+        ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
+            .opt_def_id()
+            .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+        ExprKind::MethodCall(_, _, [_other], ..) => {
+            // We can set this to true here no matter what as if it's a `MethodCall` and goes to the
+            // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
+            *needs_fully_qualified = true;
+
+            // It's a bit annoying but `typeck_results` only gives us the CURRENT body, which we
+            // have none, not of any `LocalDefId` we want, so we must call the query itself to avoid
+            // an immediate ICE
+            cx.tcx
+                .typeck(def_id)
+                .type_dependent_def_id(cmp_expr.hir_id)
+                .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+        },
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index d43e5cc9b2c..bc4ec33b733 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use if_chain::if_chain;
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -95,24 +95,23 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             return;
         }
 
-        if_chain! {
-            // Check if item is a method, called to_string and has a parameter 'self'
-            if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
-            if impl_item.ident.name == sym::to_string;
-            let decl = &signature.decl;
-            if decl.implicit_self.has_implicit_self();
-            if decl.inputs.len() == 1;
-            if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
-
+        // Check if item is a method called `to_string` and has a parameter 'self'
+        if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
+            // #11201
+            && let header = signature.header
+            && header.unsafety == Unsafety::Normal
+            && header.abi == Abi::Rust
+            && impl_item.ident.name == sym::to_string
+            && let decl = signature.decl
+            && decl.implicit_self.has_implicit_self()
+            && decl.inputs.len() == 1
+            && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
             // Check if return type is String
-            if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
-
+            && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
-
-            then {
-                show_lint(cx, impl_item);
-            }
+            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+        {
+            show_lint(cx, impl_item);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 50c433d3161..deba232bdd2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -7,11 +7,10 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
-    ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind,
-    TypeBindingKind,
+    ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
+    TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -171,6 +170,31 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             return;
         }
 
+        if let ExprKind::Let(lt) = expr.kind
+            && has_is_empty(cx, lt.init)
+            && match lt.pat.kind {
+                PatKind::Slice([], None, []) => true,
+                PatKind::Lit(lit) if is_empty_string(lit) => true,
+                _ => false,
+            }
+        {
+            let mut applicability = Applicability::MachineApplicable;
+
+            let lit1 = peel_ref_operators(cx, lt.init);
+            let lit_str =
+                Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+
+            span_lint_and_sugg(
+                cx,
+                COMPARISON_TO_EMPTY,
+                lt.span,
+                "comparison to empty slice using `if let`",
+                "using `is_empty` is clearer and more explicit",
+                format!("{lit_str}.is_empty()"),
+                applicability,
+            );
+        }
+
         if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = left.span.with_hi(right.span.hi());
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 5e62cfd70ec..9d6096ccb2a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@ mod declared_lints;
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod absolute_paths;
 mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
@@ -120,6 +121,7 @@ mod entry;
 mod enum_clike;
 mod enum_variants;
 mod equatable_if_let;
+mod error_impl_error;
 mod escape;
 mod eta_reduction;
 mod excessive_bools;
@@ -136,6 +138,7 @@ mod format_args;
 mod format_impl;
 mod format_push_string;
 mod formatting;
+mod four_forward_slashes;
 mod from_over_into;
 mod from_raw_with_void_ptr;
 mod from_str_radix_10;
@@ -272,6 +275,7 @@ mod redundant_clone;
 mod redundant_closure_call;
 mod redundant_else;
 mod redundant_field_names;
+mod redundant_locals;
 mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
@@ -909,7 +913,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
     store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
-    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
+    store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
     let disallowed_types = conf.disallowed_types.clone();
     store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
@@ -1078,6 +1082,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(visibility::Visibility));
     store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
     store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
+    store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
+    store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
+    let absolute_paths_max_segments = conf.absolute_paths_max_segments;
+    let absolute_paths_allowed_crates = conf.absolute_paths_allowed_crates.clone();
+    store.register_late_pass(move |_| {
+        Box::new(absolute_paths::AbsolutePaths {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
+        })
+    });
+    store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 852f6736585..0004a150d51 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -15,6 +15,7 @@ use rustc_hir::{
     PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -620,7 +621,7 @@ impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
 where
     F: NestedFilter<'tcx>,
 {
-    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type Map = Map<'tcx>;
     type NestedFilter = F;
 
     // for lifetimes as parameters of generics
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index a84a0a6eeb8..7b8c88235a9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -109,7 +109,7 @@ fn is_ref_iterable<'tcx>(
         && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
         && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
         && let param_env = cx.tcx.param_env(fn_id)
-        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, [])
+        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[])
         && let Some(into_iter_ty) =
             make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
         && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 744fd61bd13..dfb800ccf71 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -9,6 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition;
+use rustc_span::sym;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -51,7 +52,7 @@ pub(super) fn check<'tcx>(
             },
             [],
             _,
-        ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
+        ) if method.ident.name == sym::iter_mut => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
             Expr {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 28ee24309cc..6edca2d55f6 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -76,7 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
@@ -226,7 +226,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
                             InitializeVisitorState::DontWarn
                         }
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index d1061171e4d..6d16d188754 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -16,6 +16,7 @@ mod match_wild_enum;
 mod match_wild_err_arm;
 mod needless_match;
 mod overlapping_arms;
+mod redundant_guards;
 mod redundant_pattern_match;
 mod rest_pat_in_fully_bound_struct;
 mod significant_drop_in_scrutinee;
@@ -936,6 +937,36 @@ declare_clippy_lint! {
     "reimplementation of `filter`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for unnecessary guards in match expressions.
+    ///
+    /// ### Why is this bad?
+    /// It's more complex and much less readable. Making it part of the pattern can improve
+    /// exhaustiveness checking as well.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(x) if matches!(x, Some(1)) => ..,
+    ///     Some(x) if x == Some(2) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(Some(1)) => ..,
+    ///     Some(Some(2)) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_GUARDS,
+    complexity,
+    "checks for unnecessary guards in match expressions"
+}
+
 #[derive(Default)]
 pub struct Matches {
     msrv: Msrv,
@@ -978,6 +1009,7 @@ impl_lint_pass!(Matches => [
     TRY_ERR,
     MANUAL_MAP,
     MANUAL_FILTER,
+    REDUNDANT_GUARDS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -1025,6 +1057,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     needless_match::check_match(cx, ex, arms, expr);
                     match_on_vec_items::check(cx, ex);
                     match_str_case_mismatch::check(cx, ex, arms);
+                    redundant_guards::check(cx, arms);
 
                     if !in_constant(cx, expr.hir_id) {
                         manual_unwrap_or::check(cx, expr, ex, arms);
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
new file mode 100644
index 00000000000..6383326aa38
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -0,0 +1,190 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::visitors::{for_each_expr, is_local_used};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::ops::ControlFlow;
+
+use super::REDUNDANT_GUARDS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
+    for outer_arm in arms {
+        let Some(guard) = outer_arm.guard else {
+            continue;
+        };
+
+        // `Some(x) if matches!(x, y)`
+        if let Guard::If(if_expr) = guard
+            && let ExprKind::Match(
+                scrutinee,
+                [
+                    arm,
+                    Arm {
+                        pat: Pat {
+                            kind: PatKind::Wild,
+                            ..
+                        },
+                        ..
+                    },
+                ],
+                MatchSource::Normal,
+            ) = if_expr.kind
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                scrutinee,
+                arm.pat.span,
+                arm.guard,
+            );
+        }
+        // `Some(x) if let Some(2) = x`
+        else if let Guard::IfLet(let_expr) = guard {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                let_expr.span,
+                let_expr.init,
+                let_expr.pat.span,
+                None,
+            );
+        }
+        // `Some(x) if x == Some(2)`
+        else if let Guard::If(if_expr) = guard
+            && let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
+            && matches!(bin_op.node, BinOpKind::Eq)
+            && expr_can_be_pat(cx, pat)
+            // Ensure they have the same type. If they don't, we'd need deref coercion which isn't
+            // possible (currently) in a pattern. In some cases, you can use something like
+            // `as_deref` or similar but in general, we shouldn't lint this as it'd create an
+            // extraordinary amount of FPs.
+            //
+            // This isn't necessary in the other two checks, as they must be a pattern already.
+            && cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                local,
+                pat.span,
+                None,
+            );
+        }
+    }
+}
+
+fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
+    if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
+        let mut span = None;
+        let mut multiple_bindings = false;
+        // `each_binding` gives the `HirId` of the `Pat` itself, not the binding
+        outer_arm.pat.walk(|pat| {
+            if let PatKind::Binding(_, hir_id, _, _) = pat.kind
+                && hir_id == local
+                && span.replace(pat.span).is_some()
+            {
+                multiple_bindings = true;
+                return false;
+            }
+
+            true
+        });
+
+        // Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
+        if !multiple_bindings {
+            return span.map(|span| {
+                (
+                    span,
+                    !matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
+                )
+            });
+        }
+    }
+
+    None
+}
+
+fn emit_redundant_guards<'tcx>(
+    cx: &LateContext<'tcx>,
+    outer_arm: &Arm<'tcx>,
+    guard_span: Span,
+    local: &Expr<'_>,
+    pat_span: Span,
+    inner_guard: Option<Guard<'_>>,
+) {
+    let mut app = Applicability::MaybeIncorrect;
+    let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
+        return;
+    };
+
+    span_lint_and_then(
+        cx,
+        REDUNDANT_GUARDS,
+        guard_span.source_callsite(),
+        "redundant guard",
+        |diag| {
+            let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app);
+            diag.multipart_suggestion_verbose(
+                "try",
+                vec![
+                    if can_use_shorthand {
+                        (pat_binding, binding_replacement.into_owned())
+                    } else {
+                        (pat_binding.shrink_to_hi(), format!(": {binding_replacement}"))
+                    },
+                    (
+                        guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
+                        inner_guard.map_or_else(String::new, |guard| {
+                            let (prefix, span) = match guard {
+                                Guard::If(e) => ("if", e.span),
+                                Guard::IfLet(l) => ("if let", l.span),
+                            };
+
+                            format!(
+                                " {prefix} {}",
+                                snippet_with_applicability(cx, span, "<guard>", &mut app),
+                            )
+                        }),
+                    ),
+                ],
+                app,
+            );
+        },
+    );
+}
+
+/// Checks if the given `Expr` can also be represented as a `Pat`.
+fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    for_each_expr(expr, |expr| {
+        if match expr.kind {
+            ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
+            ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
+                // Allow ctors
+                matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
+            },
+            ExprKind::Path(qpath) => {
+                matches!(
+                    cx.qpath_res(&qpath, expr.hir_id),
+                    Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
+                )
+            },
+            ExprKind::AddrOf(..)
+            | ExprKind::Array(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Lit(..) => true,
+            _ => false,
+        } {
+            return ControlFlow::Continue(());
+        }
+
+        ControlFlow::Break(())
+    })
+    .is_none()
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index ad38f1394b4..9a7c00823b6 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -3,17 +3,19 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
-use clippy_utils::visitors::any_temporaries_need_ordered_drop;
+use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
 use clippy_utils::{higher, is_expn_of, is_trait_method};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{sym, Symbol};
+use std::fmt::Write;
+use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
@@ -201,30 +203,58 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
-        if let Some(good_method) = found_good_method(cx, arms, node_pair) {
+        if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
             let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
+            let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+
+            if let Some(guard) = maybe_guard {
+                let Guard::If(guard) = *guard else { return }; // `...is_none() && let ...` is a syntax error
+
+                // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
+                // `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs,
+                // counter to the intuition that it should be `Guard::IfLet`, so we need another check
+                // to see that there aren't any let chains anywhere in the guard, as that would break
+                // if we suggest `t.is_none() && (let X = y && z)` for:
+                // `match t { None if let X = y && z => true, _ => false }`
+                let has_nested_let_chain = for_each_expr(guard, |expr| {
+                    if matches!(expr.kind, ExprKind::Let(..)) {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(())
+                    }
+                })
+                .is_some();
+
+                if has_nested_let_chain {
+                    return;
+                }
+
+                let guard = Sugg::hir(cx, guard, "..");
+                let _ = write!(sugg, " && {}", guard.maybe_par());
+            }
+
             span_lint_and_sugg(
                 cx,
                 REDUNDANT_PATTERN_MATCHING,
                 span,
                 &format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
-                format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
+                sugg,
                 Applicability::MachineApplicable,
             );
         }
     }
 }
 
-fn found_good_method<'a>(
+fn found_good_method<'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     node: (&PatKind<'_>, &PatKind<'_>),
-) -> Option<&'a str> {
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
     match node {
         (
             PatKind::TupleStruct(ref path_left, patterns_left, _),
@@ -310,7 +340,11 @@ fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> {
     }
 }
 
-fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> {
+fn get_good_method<'tcx>(
+    cx: &LateContext<'_>,
+    arms: &'tcx [Arm<'tcx>],
+    path_left: &QPath<'_>,
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
     if let Some(name) = get_ident(path_left) {
         return match name.as_str() {
             "Ok" => {
@@ -376,16 +410,16 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
 }
 
 #[expect(clippy::too_many_arguments)]
-fn find_good_method_for_match<'a>(
+fn find_good_method_for_match<'a, 'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     path_left: &QPath<'_>,
     path_right: &QPath<'_>,
     expected_item_left: Item,
     expected_item_right: Item,
     should_be_left: &'a str,
     should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
     let first_pat = arms[0].pat;
     let second_pat = arms[1].pat;
 
@@ -403,22 +437,22 @@ fn find_good_method_for_match<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
             _ => None,
         },
         _ => None,
     }
 }
 
-fn find_good_method_for_matches_macro<'a>(
+fn find_good_method_for_matches_macro<'a, 'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     path_left: &QPath<'_>,
     expected_item_left: Item,
     should_be_left: &'a str,
     should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
     let first_pat = arms[0].pat;
 
     let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) {
@@ -429,8 +463,8 @@ fn find_good_method_for_matches_macro<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
             _ => None,
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 597a423b537..c9eaa185acc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,7 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
+use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
+use hir::{Body, HirId, MatchSource, Pat};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -10,7 +12,7 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use std::borrow::Cow;
 
 use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
@@ -48,6 +50,214 @@ fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_ar
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
 }
 
+#[derive(Debug, Copy, Clone)]
+enum OffendingFilterExpr<'tcx> {
+    /// `.filter(|opt| opt.is_some())`
+    IsSome {
+        /// The receiver expression
+        receiver: &'tcx Expr<'tcx>,
+        /// If `Some`, then this contains the span of an expression that possibly contains side
+        /// effects: `.filter(|opt| side_effect(opt).is_some())`
+        ///                         ^^^^^^^^^^^^^^^^
+        ///
+        /// We will use this later for warning the user that the suggested fix may change
+        /// the behavior.
+        side_effect_expr_span: Option<Span>,
+    },
+    /// `.filter(|res| res.is_ok())`
+    IsOk {
+        /// The receiver expression
+        receiver: &'tcx Expr<'tcx>,
+        /// See `IsSome`
+        side_effect_expr_span: Option<Span>,
+    },
+    /// `.filter(|enum| matches!(enum, Enum::A(_)))`
+    Matches {
+        /// The DefId of the variant being matched
+        variant_def_id: hir::def_id::DefId,
+    },
+}
+
+#[derive(Debug)]
+enum CalledMethod {
+    OptionIsSome,
+    ResultIsOk,
+}
+
+/// The result of checking a `map` call, returned by `OffendingFilterExpr::check_map_call`
+#[derive(Debug)]
+enum CheckResult<'tcx> {
+    Method {
+        map_arg: &'tcx Expr<'tcx>,
+        /// The method that was called inside of `filter`
+        method: CalledMethod,
+        /// See `OffendingFilterExpr::IsSome`
+        side_effect_expr_span: Option<Span>,
+    },
+    PatternMatching {
+        /// The span of the variant being matched
+        /// if let Some(s) = enum
+        ///        ^^^^^^^
+        variant_span: Span,
+        /// if let Some(s) = enum
+        ///             ^
+        variant_ident: Ident,
+    },
+}
+
+impl<'tcx> OffendingFilterExpr<'tcx> {
+    pub fn check_map_call(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        map_body: &'tcx Body<'tcx>,
+        map_param_id: HirId,
+        filter_param_id: HirId,
+        is_filter_param_ref: bool,
+    ) -> Option<CheckResult<'tcx>> {
+        match *self {
+            OffendingFilterExpr::IsSome {
+                receiver,
+                side_effect_expr_span,
+            }
+            | OffendingFilterExpr::IsOk {
+                receiver,
+                side_effect_expr_span,
+            } => {
+                // check if closure ends with expect() or unwrap()
+                if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind
+                    && matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or)
+                    // .map(|y| f(y).copied().unwrap())
+                    //          ~~~~
+                    && let map_arg_peeled = match map_arg.kind {
+                        ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
+                            original_arg
+                        },
+                        _ => map_arg,
+                    }
+                    // .map(|y| y[.acceptable_method()].unwrap())
+                    && let simple_equal = (path_to_local_id(receiver, filter_param_id)
+                        && path_to_local_id(map_arg_peeled, map_param_id))
+                    && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
+                        // in `filter(|x| ..)`, replace `*x` with `x`
+                        let a_path = if_chain! {
+                            if !is_filter_param_ref;
+                            if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
+                            then { expr_path } else { a }
+                        };
+                        // let the filter closure arg and the map closure arg be equal
+                        path_to_local_id(a_path, filter_param_id)
+                            && path_to_local_id(b, map_param_id)
+                            && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+                    })
+                    && (simple_equal
+                        || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
+                {
+                    Some(CheckResult::Method {
+                        map_arg,
+                        side_effect_expr_span,
+                        method: match self {
+                            OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome,
+                            OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk,
+                            OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"),
+                        }
+                    })
+                } else {
+                    None
+                }
+            },
+            OffendingFilterExpr::Matches { variant_def_id } => {
+                let expr_uses_local = |pat: &Pat<'_>, expr: &Expr<'_>| {
+                    if let PatKind::TupleStruct(QPath::Resolved(_, path), [subpat], _) = pat.kind
+                        && let PatKind::Binding(_, local_id, ident, _) = subpat.kind
+                        && path_to_local_id(expr.peel_blocks(), local_id)
+                        && let Some(local_variant_def_id) = path.res.opt_def_id()
+                        && local_variant_def_id == variant_def_id
+                    {
+                        Some((ident, pat.span))
+                    } else {
+                        None
+                    }
+                };
+
+                // look for:
+                // `if let Variant   (v) =         enum { v } else { unreachable!() }`
+                //         ^^^^^^^    ^            ^^^^            ^^^^^^^^^^^^^^^^^^
+                //    variant_span  variant_ident  scrutinee       else_ (blocks peeled later)
+                // OR
+                // `match enum {   Variant       (v) => v,      _ => unreachable!() }`
+                //        ^^^^     ^^^^^^^        ^                  ^^^^^^^^^^^^^^
+                //     scrutinee  variant_span  variant_ident        else_
+                let (scrutinee, else_, variant_ident, variant_span) =
+                    match higher::IfLetOrMatch::parse(cx, map_body.value) {
+                        // For `if let` we want to check that the variant matching arm references the local created by its pattern
+                        Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
+                            if let Some((ident, span)) = expr_uses_local(pat, then) =>
+                        {
+                            (sc, else_, ident, span)
+                        },
+                        // For `match` we want to check that the "else" arm is the wildcard (`_`) pattern
+                        // and that the variant matching arm references the local created by its pattern
+                        Some(higher::IfLetOrMatch::Match(sc, [arm, wild_arm], MatchSource::Normal))
+                            if let PatKind::Wild = wild_arm.pat.kind
+                                && let Some((ident, span)) = expr_uses_local(arm.pat, arm.body.peel_blocks()) =>
+                        {
+                            (sc, wild_arm.body, ident, span)
+                        },
+                        _ => return None,
+                    };
+
+                if path_to_local_id(scrutinee, map_param_id)
+                    // else branch should be a `panic!` or `unreachable!` macro call
+                    && let Some(mac) = root_macro_call(else_.peel_blocks().span)
+                    && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable))
+                {
+                    Some(CheckResult::PatternMatching { variant_span, variant_ident })
+                } else {
+                    None
+                }
+            },
+        }
+    }
+
+    fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -> Option<Self> {
+        if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind
+            && let Some(recv_ty) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
+        {
+            // we still want to lint if the expression possibly contains side effects,
+            // *but* it can't be machine-applicable then, because that can change the behavior of the program:
+            // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap())
+            // vs.
+            // .filter_map(|x| effect(x))
+            // 
+            // the latter only calls `effect` once
+            let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
+
+            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did())
+                && path.ident.name == sym!(is_some)
+            {
+                Some(Self::IsSome { receiver, side_effect_expr_span })
+            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did())
+                && path.ident.name == sym!(is_ok)
+            {
+                Some(Self::IsOk { receiver, side_effect_expr_span })
+            } else {
+                None
+            }
+        } else if let Some(macro_call) = root_macro_call(expr.span)
+            && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro)
+            // we know for a fact that the wildcard pattern is the second arm
+            && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
+            && path_to_local_id(scrutinee, filter_param_id)
+            && let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind
+            && let Some(variant_def_id) = path.res.opt_def_id()
+        {
+            Some(OffendingFilterExpr::Matches { variant_def_id })
+        } else {
+            None
+        }
+    }
+}
+
 /// is `filter(|x| x.is_some()).map(|x| x.unwrap())`
 fn is_filter_some_map_unwrap(
     cx: &LateContext<'_>,
@@ -102,55 +312,18 @@ pub(super) fn check(
         } else {
             (filter_param.pat, false)
         };
-        // closure ends with is_some() or is_ok()
+
         if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-        if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
-        if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
-        if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
-            Some(false)
-        } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
-            Some(true)
-        } else {
-            None
-        };
-        if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+        if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id);
 
-        // ...map(|x| ...unwrap())
         if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
         let map_body = cx.tcx.hir().body(map_body_id);
         if let [map_param] = map_body.params;
         if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
-        // closure ends with expect() or unwrap()
-        if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
-        if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
-
-        // .filter(..).map(|y| f(y).copied().unwrap())
-        //                     ~~~~
-        let map_arg_peeled = match map_arg.kind {
-            ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
-                original_arg
-            },
-            _ => map_arg,
-        };
 
-        // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
-        let simple_equal = path_to_local_id(filter_arg, filter_param_id)
-            && path_to_local_id(map_arg_peeled, map_param_id);
+        if let Some(check_result) =
+            offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref);
 
-        let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-            // in `filter(|x| ..)`, replace `*x` with `x`
-            let a_path = if_chain! {
-                if !is_filter_param_ref;
-                if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
-                then { expr_path } else { a }
-            };
-            // let the filter closure arg and the map closure arg be equal
-            path_to_local_id(a_path, filter_param_id)
-                && path_to_local_id(b, map_param_id)
-                && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
-        };
-
-        if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
         then {
             let span = filter_span.with_hi(expr.span.hi());
             let (filter_name, lint) = if is_find {
@@ -159,22 +332,53 @@ pub(super) fn check(
                 ("filter", MANUAL_FILTER_MAP)
             };
             let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
-            let (to_opt, deref) = if is_result {
-                (".ok()", String::new())
-            } else {
-                let derefs = cx.typeck_results()
-                    .expr_adjustments(map_arg)
-                    .iter()
-                    .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                    .count();
 
-                ("", "*".repeat(derefs))
+            let (sugg, note_and_span, applicability) = match check_result {
+                CheckResult::Method { map_arg, method, side_effect_expr_span } => {
+                    let (to_opt, deref) = match method {
+                        CalledMethod::ResultIsOk => (".ok()", String::new()),
+                        CalledMethod::OptionIsSome => {
+                            let derefs = cx.typeck_results()
+                                .expr_adjustments(map_arg)
+                                .iter()
+                                .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
+                                .count();
+
+                            ("", "*".repeat(derefs))
+                        }
+                    };
+
+                    let sugg = format!(
+                        "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
+                        snippet(cx, map_arg.span, ".."),
+                    );
+                    let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span {
+                        let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \
+                            because this expression potentially contains side effects and will only execute once";
+
+                        (Some((note, span)), Applicability::MaybeIncorrect)
+                    } else {
+                        (None, Applicability::MachineApplicable)
+                    };
+
+                    (sugg, note_and_span, applicability)
+                }
+                CheckResult::PatternMatching { variant_span, variant_ident } => {
+                    let pat = snippet(cx, variant_span, "<pattern>");
+
+                    (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
+                        {pat} => Some({variant_ident}), \
+                        _ => None \
+                    }})"), None, Applicability::MachineApplicable)
+                }
             };
-            let sugg = format!(
-                "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
-                snippet(cx, map_arg.span, ".."),
-            );
-            span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
+            span_lint_and_then(cx, lint, span, &msg, |diag| {
+                diag.span_suggestion(span, "try", sugg, applicability);
+
+                if let Some((note, span)) = note_and_span {
+                    diag.span_note(span, note);
+                }
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
new file mode 100644
index 00000000000..4aee22a4afc
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::BOOL_THEN;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_span::{sym, Span};
+
+use super::FILTER_MAP_BOOL_THEN;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
+    if !in_external_macro(cx.sess(), expr.span)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let ExprKind::Closure(closure) = arg.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && let value = peel_blocks(body.value)
+        // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
+        // `inputs` and `params` here as we need both the type and the span
+        && let param_ty = closure.fn_decl.inputs[0]
+        && let param = body.params[0]
+        && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs())
+        && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
+        && let ExprKind::Closure(then_closure) = then_arg.kind
+        && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
+        && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+        && match_def_path(cx, def_id, &BOOL_THEN)
+        && !is_from_proc_macro(cx, expr)
+        && let Some(param_snippet) = snippet_opt(cx, param.span)
+        && let Some(filter) = snippet_opt(cx, recv.span)
+        && let Some(map) = snippet_opt(cx, then_body.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            FILTER_MAP_BOOL_THEN,
+            call_span,
+            "usage of `bool::then` in `filter_map`",
+            "use `filter` then `map` instead",
+            format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
new file mode 100644
index 00000000000..1f8863f8521
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -0,0 +1,33 @@
+use super::FORMAT_COLLECT;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node};
+use clippy_utils::ty::is_type_lang_item;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+/// Same as `peel_blocks` but only actually considers blocks that are not from an expansion.
+/// This is needed because always calling `peel_blocks` would otherwise remove parts of the
+/// `format!` macro, which would cause `root_macro_call_first_node` to return `None`.
+fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    match expr.kind {
+        ExprKind::Block(block, _) if !expr.span.from_expansion() => peel_non_expn_blocks(block.expr?),
+        _ => Some(expr),
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
+    if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+        && let ExprKind::Closure(closure) = map_arg.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && let Some(value) = peel_non_expn_blocks(body.value)
+        && let Some(mac) = root_macro_call_first_node(cx, value)
+        && is_format_macro(cx, mac.def_id)
+    {
+        span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| {
+            diag.span_help(map_span, "call `fold` instead")
+                .span_help(value.span.source_callsite(), "... and use the `write!` macro here")
+                .note("this can be written more efficiently by appending to a `String` directly");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
new file mode 100644
index 00000000000..6b696b42a69
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -0,0 +1,34 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_from_proc_macro, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::ITER_SKIP_ZERO;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
+    if !expr.span.from_expansion()
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
+            if let Constant::Int(arg) = constant {
+                Some(arg)
+            } else {
+                None
+            }
+        })
+        && arg == 0
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_then(cx, ITER_SKIP_ZERO, arg_expr.span, "usage of `.skip(0)`", |diag| {
+            diag.span_suggestion(
+                arg_expr.span,
+                "if you meant to skip the first element, use",
+                "1",
+                Applicability::MaybeIncorrect,
+            )
+            .note("this call to `skip` does nothing and is useless; remove it");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 123ab520e48..dd694ce7393 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -21,11 +21,13 @@ mod expect_used;
 mod extend_with_drain;
 mod filetype_is_file;
 mod filter_map;
+mod filter_map_bool_then;
 mod filter_map_identity;
 mod filter_map_next;
 mod filter_next;
 mod flat_map_identity;
 mod flat_map_option;
+mod format_collect;
 mod from_iter_instead_of_collect;
 mod get_first;
 mod get_last_with_len;
@@ -44,6 +46,7 @@ mod iter_nth_zero;
 mod iter_on_single_or_empty_collections;
 mod iter_overeager_cloned;
 mod iter_skip_next;
+mod iter_skip_zero;
 mod iter_with_drain;
 mod iterator_step_by_zero;
 mod manual_next_back;
@@ -73,6 +76,7 @@ mod or_then_unwrap;
 mod path_buf_push_overwrite;
 mod range_zip_with_len;
 mod read_line_without_trim;
+mod readonly_write_lock;
 mod repeat_once;
 mod search_is_some;
 mod seek_from_current;
@@ -85,6 +89,7 @@ mod skip_while_next;
 mod stable_sort_primitive;
 mod str_splitn;
 mod string_extend_chars;
+mod string_lit_chars_any;
 mod suspicious_command_arg_space;
 mod suspicious_map;
 mod suspicious_splitn;
@@ -100,7 +105,6 @@ mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
-mod unwrap_or_else_default;
 mod unwrap_used;
 mod useless_asref;
 mod utils;
@@ -114,7 +118,7 @@ use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
@@ -473,29 +477,40 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and
-    /// `Result` values.
+    /// Checks for usages of the following functions with an argument that constructs a default value
+    /// (e.g., `Default::default` or `String::new`):
+    /// - `unwrap_or`
+    /// - `unwrap_or_else`
+    /// - `or_insert`
+    /// - `or_insert_with`
     ///
     /// ### Why is this bad?
-    /// Readability, these can be written as `_.unwrap_or_default`, which is
-    /// simpler and more concise.
+    /// Readability. Using `unwrap_or_default` in place of `unwrap_or`/`unwrap_or_else`, or `or_default`
+    /// in place of `or_insert`/`or_insert_with`, is simpler and more concise.
+    ///
+    /// ### Known problems
+    /// In some cases, the argument of `unwrap_or`, etc. is needed for type inference. The lint uses a
+    /// heuristic to try to identify such cases. However, the heuristic can produce false negatives.
     ///
     /// ### Examples
     /// ```rust
     /// # let x = Some(1);
-    /// x.unwrap_or_else(Default::default);
-    /// x.unwrap_or_else(u32::default);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
+    /// x.unwrap_or(Default::default());
+    /// map.entry(42).or_insert_with(String::new);
     /// ```
     ///
     /// Use instead:
     /// ```rust
     /// # let x = Some(1);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
     /// x.unwrap_or_default();
+    /// map.entry(42).or_default();
     /// ```
     #[clippy::version = "1.56.0"]
-    pub UNWRAP_OR_ELSE_DEFAULT,
+    pub UNWRAP_OR_DEFAULT,
     style,
-    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
+    "using `.unwrap_or`, etc. with an argument that constructs a default value"
 }
 
 declare_clippy_lint! {
@@ -3378,6 +3393,152 @@ declare_clippy_lint! {
     "calling `Stdin::read_line`, then trying to parse it without first trimming"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `<string_lit>.chars().any(|i| i == c)`.
+    ///
+    /// ### Why is this bad?
+    /// It's significantly slower than using a pattern instead, like
+    /// `matches!(c, '\\' | '.' | '+')`.
+    ///
+    /// Despite this being faster, this is not `perf` as this is pretty common, and is a rather nice
+    /// way to check if a `char` is any in a set. In any case, this `restriction` lint is available
+    /// for situations where that additional performance is absolutely necessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let c = 'c';
+    /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let c = 'c';
+    /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub STRING_LIT_CHARS_ANY,
+    restriction,
+    "checks for `<string_lit>.chars().any(|i| i == c)`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.map(|_| format!(..)).collect::<String>()`.
+    ///
+    /// ### Why is this bad?
+    /// This allocates a new string for every element in the iterator.
+    /// This can be done more efficiently by creating the `String` once and appending to it in `Iterator::fold`,
+    /// using either the `write!` macro which supports exactly the same syntax as the `format!` macro,
+    /// or concatenating with `+` in case the iterator yields `&str`/`String`.
+    ///
+    /// Note also that `write!`-ing into a `String` can never fail, despite the return type of `write!` being `std::fmt::Result`,
+    /// so it can be safely ignored or unwrapped.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn hex_encode(bytes: &[u8]) -> String {
+    ///     bytes.iter().map(|b| format!("{b:02X}")).collect()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::fmt::Write;
+    /// fn hex_encode(bytes: &[u8]) -> String {
+    ///     bytes.iter().fold(String::new(), |mut output, b| {
+    ///         let _ = write!(output, "{b:02X}");
+    ///         output
+    ///     })
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FORMAT_COLLECT,
+    perf,
+    "`format!`ing every element in a collection, then collecting the strings into a new `String`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.skip(0)` on iterators.
+    ///
+    /// ### Why is this bad?
+    /// This was likely intended to be `.skip(1)` to skip the first element, as `.skip(0)` does
+    /// nothing. If not, the call should be removed.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let v = vec![1, 2, 3];
+    /// let x = v.iter().skip(0).collect::<Vec<_>>();
+    /// let y = v.iter().collect::<Vec<_>>();
+    /// assert_eq!(x, y);
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ITER_SKIP_ZERO,
+    correctness,
+    "disallows `.skip(0)`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `bool::then` in `Iterator::filter_map`.
+    ///
+    /// ### Why is this bad?
+    /// This can be written with `filter` then `map` instead, which would reduce nesting and
+    /// separates the filtering from the transformation phase. This comes with no cost to
+    /// performance and is just cleaner.
+    ///
+    /// ### Limitations
+    /// Does not lint `bool::then_some`, as it eagerly evaluates its arguments rather than lazily.
+    /// This can create differing behavior, so better safe than sorry.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FILTER_MAP_BOOL_THEN,
+    style,
+    "checks for usage of `bool::then` in `Iterator::filter_map`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for calls to `RwLock::write` where the lock is only used for reading.
+    ///
+    /// ### Why is this bad?
+    /// The write portion of `RwLock` is exclusive, meaning that no other thread
+    /// can access the lock while this writer is active.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.write().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.read().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub READONLY_WRITE_LOCK,
+    nursery,
+    "acquiring a write lock when a read lock would work"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3408,7 +3569,7 @@ impl_lint_pass!(Methods => [
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
     OK_EXPECT,
-    UNWRAP_OR_ELSE_DEFAULT,
+    UNWRAP_OR_DEFAULT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
     OPTION_MAP_OR_NONE,
@@ -3512,6 +3673,11 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_LITERAL_UNWRAP,
     DRAIN_COLLECT,
     MANUAL_TRY_FOLD,
+    FORMAT_COLLECT,
+    STRING_LIT_CHARS_ANY,
+    ITER_SKIP_ZERO,
+    FILTER_MAP_BOOL_THEN,
+    READONLY_WRITE_LOCK
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3666,8 +3832,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                    .self_ty();
+                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
                 wrong_self_convention::check(
                     cx,
                     item.ident.name.as_str(),
@@ -3684,8 +3849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.owner_id);
-            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                .self_ty();
+            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
             if !ret_ty.contains(self_ty);
 
             then {
@@ -3733,8 +3897,9 @@ impl Methods {
                         Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
                             iter_cloned_collect::check(cx, name, expr, recv2);
                         },
-                        Some(("map", m_recv, [m_arg], _, _)) => {
+                        Some(("map", m_recv, [m_arg], m_ident_span, _)) => {
                             map_collect_result_unit::check(cx, expr, m_recv, m_arg);
+                            format_collect::check(cx, expr, m_arg, m_ident_span);
                         },
                         Some(("take", take_self_arg, [take_arg], _, _)) => {
                             if self.msrv.meets(msrvs::STR_REPEAT) {
@@ -3790,6 +3955,7 @@ impl Methods {
                 },
                 ("filter_map", [arg]) => {
                     unnecessary_filter_map::check(cx, expr, arg, name);
+                    filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
                 ("find_map", [arg]) => {
@@ -3833,7 +3999,16 @@ impl Methods {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
-                ("last", []) | ("skip", [_]) => {
+                ("skip", [arg]) => {
+                    iter_skip_zero::check(cx, expr, arg);
+
+                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
+                        if let ("cloned", []) = (name2, args2) {
+                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
+                        }
+                    }
+                }
+                ("last", []) => {
                     if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
@@ -3885,6 +4060,13 @@ impl Methods {
                         }
                     }
                 },
+                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
+                    && let body = cx.tcx.hir().body(arg.body)
+                    && let [param] = body.params
+                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
+                {
+                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                }
                 ("nth", [n_arg]) => match method_call(recv) {
                     Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
                     Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
@@ -4027,7 +4209,6 @@ impl Methods {
                         Some(("map", recv, [map_arg], _, _))
                             if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
                         _ => {
-                            unwrap_or_else_default::check(cx, expr, recv, u_arg);
                             unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
                         },
                     }
@@ -4040,6 +4221,9 @@ impl Methods {
                         range_zip_with_len::check(cx, expr, iter_recv, arg);
                     }
                 },
+                ("write", []) => {
+                    readonly_write_lock::check(cx, expr, recv);
+                }
                 _ => {},
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 9165c1248f0..8b2f57160af 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,16 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{self, sym, Symbol};
+use {rustc_ast as ast, rustc_hir as hir};
 
-use super::OR_FUN_CALL;
+use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
 
 /// Checks for the `OR_FUN_CALL` lint.
 #[allow(clippy::too_many_lines)]
@@ -24,53 +25,72 @@ pub(super) fn check<'tcx>(
 ) {
     /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
     /// `or_insert(T::new())` or `or_insert(T::default())`.
+    /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
+    /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
+        receiver: &hir::Expr<'_>,
         fun: &hir::Expr<'_>,
-        arg: &hir::Expr<'_>,
-        or_has_args: bool,
+        call_expr: Option<&hir::Expr<'_>>,
         span: Span,
         method_span: Span,
     ) -> bool {
-        let is_default_default = || is_trait_item(cx, fun, sym::Default);
+        if !expr_type_is_certain(cx, receiver) {
+            return false;
+        }
 
-        let implements_default = |arg, default_trait_id| {
-            let arg_ty = cx.typeck_results().expr_ty(arg);
-            implements_trait(cx, arg_ty, default_trait_id, &[])
+        let is_new = |fun: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(ref qpath) = fun.kind {
+                let path = last_path_segment(qpath).ident.name;
+                matches!(path, sym::new)
+            } else {
+                false
+            }
         };
 
-        if_chain! {
-            if !or_has_args;
-            if let Some(sugg) = match name {
-                "unwrap_or" => Some("unwrap_or_default"),
-                "or_insert" => Some("or_default"),
-                _ => None,
-            };
-            if let hir::ExprKind::Path(ref qpath) = fun.kind;
-            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
-            let path = last_path_segment(qpath).ident.name;
-            // needs to target Default::default in particular or be *::new and have a Default impl
-            // available
-            if (matches!(path, kw::Default) && is_default_default())
-                || (matches!(path, sym::new) && implements_default(arg, default_trait_id));
-
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    OR_FUN_CALL,
-                    method_span.with_hi(span.hi()),
-                    &format!("use of `{name}` followed by a call to `{path}`"),
-                    "try",
-                    format!("{sugg}()"),
-                    Applicability::MachineApplicable,
-                );
-
-                true
+        let output_type_implements_default = |fun| {
+            let fun_ty = cx.typeck_results().expr_ty(fun);
+            if let ty::FnDef(def_id, args) = fun_ty.kind() {
+                let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output();
+                cx.tcx
+                    .get_diagnostic_item(sym::Default)
+                    .map_or(false, |default_trait_id| {
+                        implements_trait(cx, output_ty, default_trait_id, &[])
+                    })
             } else {
                 false
             }
+        };
+
+        let sugg = match (name, call_expr.is_some()) {
+            ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
+            ("or_insert", true) | ("or_insert_with", false) => "or_default",
+            _ => return false,
+        };
+
+        // needs to target Default::default in particular or be *::new and have a Default impl
+        // available
+        if (is_new(fun) && output_type_implements_default(fun))
+            || match call_expr {
+                Some(call_expr) => is_default_equivalent(cx, call_expr),
+                None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun),
+            }
+        {
+            span_lint_and_sugg(
+                cx,
+                UNWRAP_OR_DEFAULT,
+                method_span.with_hi(span.hi()),
+                &format!("use of `{name}` to construct default value"),
+                "try",
+                format!("{sugg}()"),
+                Applicability::MachineApplicable,
+            );
+
+            true
+        } else {
+            false
         }
     }
 
@@ -168,11 +188,16 @@ pub(super) fn check<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
+                if or_has_args
+                    || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
+                {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
                 }
             },
+            hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
+                check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
+            },
             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
                 check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
             },
@@ -189,3 +214,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+            && ident.name == sym::to_string
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index 8add0656101..81f9e2a77fc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -35,8 +35,8 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                 && segment.ident.name == sym!(parse)
                 && let parse_result_ty = cx.typeck_results().expr_ty(parent)
                 && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
-                && let ty::Adt(_, substs) = parse_result_ty.kind()
-                && let Some(ok_ty) = substs[0].as_type()
+                && let ty::Adt(_, args) = parse_result_ty.kind()
+                && let Some(ok_ty) = args[0].as_type()
                 && parse_fails_on_trailing_newline(ok_ty)
             {
                 let local_snippet = snippet(cx, expr.span, "<expr>");
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
new file mode 100644
index 00000000000..e3ec921da0c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -0,0 +1,52 @@
+use super::READONLY_WRITE_LOCK;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::mir::{enclosing_mir, visit_local_usage};
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{Location, START_BLOCK};
+use rustc_span::sym;
+
+fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::MethodCall(path, receiver, ..) = expr.kind
+        && path.ident.name == sym::unwrap
+    {
+        is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)
+    } else {
+        false
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
+        && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id)
+        && is_unwrap_call(cx, unwrap_call_expr)
+        && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
+        && let Node::Local(local) = parent
+        && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
+        && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| {
+            local.span.contains(decl.source_info.span)
+        })
+        && let Some(usages) = visit_local_usage(&[local], mir, Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        })
+        && let [usage] = usages.as_slice()
+    {
+        let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
+
+        if writer_never_mutated {
+            span_lint_and_sugg(
+                cx,
+                READONLY_WRITE_LOCK,
+                expr.span,
+                "this write lock is used only for reading",
+                "consider using a read lock instead",
+                format!("{}.read()", snippet(cx, receiver.span, "<receiver>")),
+                Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
new file mode 100644
index 00000000000..70da6ad58bd
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
@@ -0,0 +1,58 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{Msrv, MATCHES_MACRO};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
+use itertools::Itertools;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, Param, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::STRING_LIT_CHARS_ANY;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &Expr<'_>,
+    param: &'tcx Param<'tcx>,
+    body: &Expr<'_>,
+    msrv: &Msrv,
+) {
+    if msrv.meets(MATCHES_MACRO)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let PatKind::Binding(_, arg, _, _) = param.pat.kind
+        && let ExprKind::Lit(lit_kind) = recv.kind
+        && let LitKind::Str(val, _) = lit_kind.node
+        && let ExprKind::Binary(kind, lhs, rhs) = body.kind
+        && let BinOpKind::Eq = kind.node
+        && let Some(lhs_path) = path_to_local(lhs)
+        && let Some(rhs_path) = path_to_local(rhs)
+        && let scrutinee = match (lhs_path == arg, rhs_path == arg) {
+            (true, false) => rhs,
+            (false, true) => lhs,
+            _ => return,
+        }
+        && !is_from_proc_macro(cx, expr)
+        && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span)
+    {
+        // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then
+        // something like `r"\"` will become `'\'`, which is of course invalid
+        let pat_snip = val.as_str().chars().map(|c| format!("{c:?}")).join(" | ");
+
+        span_lint_and_then(
+            cx,
+            STRING_LIT_CHARS_ANY,
+            expr.span,
+            "usage of `.chars().any(...)` to check if a char matches any from a string literal",
+            |diag| {
+                diag.span_suggestion_verbose(
+                    expr.span,
+                    "use `matches!(...)` instead",
+                    format!("matches!({scrutinee_snip}, {pat_snip})"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
index 35137c97101..3404bdfe79b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -24,9 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
 
     if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last()
         && let ty::Ref(_, ty, _) = recv_ty.kind()
-        && let ty::Adt(adt, substs) = ty.kind()
+        && let ty::Adt(adt, args) = ty.kind()
         && adt.is_box()
-        && is_dyn_any(cx, substs.type_at(0))
+        && is_dyn_any(cx, args.type_at(0))
     {
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index cc64a2e7948..fabf3fa0c0c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -77,6 +77,16 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             }
             (true, true)
         },
+        hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
+            if segment.ident.name == sym!(then_some)
+                && cx.typeck_results().expr_ty(recv).is_bool()
+                && path_to_local_id(arg, arg_id)
+            {
+                (false, true)
+            } else {
+                (true, true)
+            }
+        },
         hir::ExprKind::Block(block, _) => block
             .expr
             .as_ref()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 111bcaaecec..937aac8d25e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -3,6 +3,8 @@ use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
@@ -22,6 +24,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
     }
 }
 
+#[expect(clippy::too_many_lines)]
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
@@ -84,6 +87,34 @@ pub(super) fn check(
                 }
                 Some(suggs)
             },
+            ("None", "unwrap_or_default", _) => {
+                let ty = cx.typeck_results().expr_ty(expr);
+                let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
+                    with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
+                } else {
+                    "Default".to_string()
+                };
+                Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
+            },
+            ("None", "unwrap_or", _) => Some(vec![
+                (expr.span.with_hi(args[0].span.lo()), String::new()),
+                (expr.span.with_lo(args[0].span.hi()), String::new()),
+            ]),
+            ("None", "unwrap_or_else", _) => match args[0].kind {
+                hir::ExprKind::Closure(hir::Closure {
+                    fn_decl:
+                        hir::FnDecl {
+                            output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
+                            ..
+                        },
+                    ..
+                }) => Some(vec![
+                    (expr.span.with_hi(span.hi()), String::new()),
+                    (expr.span.with_lo(args[0].span.hi()), String::new()),
+                ]),
+                _ => None,
+            },
+            _ if call_args.is_empty() => None,
             (_, _, Some(_)) => None,
             ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
                 (
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
deleted file mode 100644
index 474a33b67e1..00000000000
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
-
-use super::UNWRAP_OR_ELSE_DEFAULT;
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_default_equivalent_call;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::{sym, symbol};
-
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    recv: &'tcx hir::Expr<'_>,
-    u_arg: &'tcx hir::Expr<'_>,
-) {
-    // something.unwrap_or_else(Default::default)
-    // ^^^^^^^^^- recv          ^^^^^^^^^^^^^^^^- u_arg
-    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
-    let recv_ty = cx.typeck_results().expr_ty(recv);
-    let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
-    let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
-
-    if_chain! {
-        if is_option || is_result;
-        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-
-            span_lint_and_sugg(
-                cx,
-                UNWRAP_OR_ELSE_DEFAULT,
-                expr.span,
-                "use of `.unwrap_or_else(..)` to construct default value",
-                "try",
-                format!(
-                    "{}.unwrap_or_default()",
-                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-                ),
-                applicability,
-            );
-        }
-    }
-}
-
-fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
-        let body = cx.tcx.hir().body(body);
-
-        if body.params.is_empty()
-            && let hir::Expr{ kind, .. } = &body.value
-            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
-            && ident == &symbol::Ident::from_str("to_string")
-            && let hir::Expr{ kind, .. } = self_arg
-            && let hir::ExprKind::Lit(lit) = kind
-            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
-        {
-            return true;
-        }
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 2a60f2faca0..c79a1a7b9d4 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -129,6 +129,14 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
                 return;
             }
 
+            // `struct Array<T, const N: usize>([T; N])`
+            //                        ^
+            if let Node::GenericParam(generic_param) = node
+                && let GenericParamKind::Const { .. } = generic_param.kind
+            {
+                return;
+            }
+
             if is_from_proc_macro(cx, &ident) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d323a16c2a7..c634de960d1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -1,16 +1,18 @@
 use super::needless_pass_by_value::requires_exact_signature;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
-use clippy_utils::{is_from_proc_macro, is_self};
-use if_chain::if_chain;
+use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind};
+use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
+use rustc_hir::{Body, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::associated_body;
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, UpvarId, UpvarPath};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
@@ -46,20 +48,24 @@ declare_clippy_lint! {
     "using a `&mut` argument when it's not mutated"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessPassByRefMut {
+#[derive(Clone)]
+pub struct NeedlessPassByRefMut<'tcx> {
     avoid_breaking_exported_api: bool,
+    used_fn_def_ids: FxHashSet<LocalDefId>,
+    fn_def_ids_to_maybe_unused_mut: FxIndexMap<LocalDefId, Vec<rustc_hir::Ty<'tcx>>>,
 }
 
-impl NeedlessPassByRefMut {
+impl NeedlessPassByRefMut<'_> {
     pub fn new(avoid_breaking_exported_api: bool) -> Self {
         Self {
             avoid_breaking_exported_api,
+            used_fn_def_ids: FxHashSet::default(),
+            fn_def_ids_to_maybe_unused_mut: FxIndexMap::default(),
         }
     }
 }
 
-impl_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]);
+impl_lint_pass!(NeedlessPassByRefMut<'_> => [NEEDLESS_PASS_BY_REF_MUT]);
 
 fn should_skip<'tcx>(
     cx: &LateContext<'tcx>,
@@ -87,12 +93,12 @@ fn should_skip<'tcx>(
     is_from_proc_macro(cx, &input)
 }
 
-impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
+impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
         kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
+        decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'_>,
         span: Span,
         fn_def_id: LocalDefId,
@@ -102,17 +108,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
         }
 
         let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
-
-        match kind {
+        let is_async = match kind {
             FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
+                header.is_async()
             },
-            FnKind::Method(..) => (),
+            FnKind::Method(.., sig) => sig.header.is_async(),
             FnKind::Closure => return,
-        }
+        };
 
         // Exclude non-inherent impls
         if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
@@ -128,63 +134,89 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
         let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
 
         // If there are no `&mut` argument, no need to go any further.
-        if !decl
+        let mut it = decl
             .inputs
             .iter()
             .zip(fn_sig.inputs())
             .zip(body.params)
-            .any(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-        {
+            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
+            .peekable();
+        if it.peek().is_none() {
             return;
         }
-
         // Collect variables mutably used and spans which will need dereferencings from the
         // function body.
         let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
             let mut ctx = MutablyUsedVariablesCtxt::default();
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+            if is_async {
+                let closures = ctx.async_closures.clone();
+                let hir = cx.tcx.hir();
+                for closure in closures {
+                    ctx.prev_bind = None;
+                    ctx.prev_move_to_closure.clear();
+                    if let Some(body) = hir
+                        .find_by_def_id(closure)
+                        .and_then(associated_body)
+                        .map(|(_, body_id)| hir.body(body_id))
+                    {
+                        euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results())
+                            .consume_body(body);
+                    }
+                }
+            }
             ctx
         };
-
-        let mut it = decl
-            .inputs
-            .iter()
-            .zip(fn_sig.inputs())
-            .zip(body.params)
-            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-            .peekable();
-        if it.peek().is_none() {
-            return;
-        }
-        let show_semver_warning = self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id);
         for ((&input, &_), arg) in it {
             // Only take `&mut` arguments.
-            if_chain! {
-                if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind;
-                if !mutably_used_vars.contains(&canonical_id);
-                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind;
-                then {
-                    // If the argument is never used mutably, we emit the warning.
-                    let sp = input.span;
-                    span_lint_and_then(
+            if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind
+                && !mutably_used_vars.contains(&canonical_id)
+            {
+                self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input);
+            }
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor {
+            cx,
+            used_fn_def_ids: &mut self.used_fn_def_ids,
+        });
+
+        for (fn_def_id, unused) in self
+            .fn_def_ids_to_maybe_unused_mut
+            .iter()
+            .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
+        {
+            let show_semver_warning =
+                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
+
+            let mut is_cfged = None;
+            for input in unused {
+                // If the argument is never used mutably, we emit the warning.
+                let sp = input.span;
+                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind {
+                    let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id));
+                    span_lint_hir_and_then(
                         cx,
                         NEEDLESS_PASS_BY_REF_MUT,
+                        cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id),
                         sp,
                         "this argument is a mutable reference, but not used mutably",
                         |diag| {
                             diag.span_suggestion(
                                 sp,
                                 "consider changing to".to_string(),
-                                format!(
-                                    "&{}",
-                                    snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),
-                                ),
+                                format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
                             if show_semver_warning {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
+                            if *is_cfged {
+                                diag.note("this is cfg-gated and may require further changes");
+                            }
                         },
                     );
                 }
@@ -197,7 +229,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
 struct MutablyUsedVariablesCtxt {
     mutably_used_vars: HirIdSet,
     prev_bind: Option<HirId>,
+    prev_move_to_closure: HirIdSet,
     aliases: HirIdMap<HirId>,
+    async_closures: FxHashSet<LocalDefId>,
 }
 
 impl MutablyUsedVariablesCtxt {
@@ -213,16 +247,27 @@ impl MutablyUsedVariablesCtxt {
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
     fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
         if let euv::Place {
-            base: euv::PlaceBase::Local(vid),
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
             base_ty,
             ..
         } = &cmt.place
         {
             if let Some(bind_id) = self.prev_bind.take() {
-                self.aliases.insert(bind_id, *vid);
-            } else if matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) {
+                if bind_id != *vid {
+                    self.aliases.insert(bind_id, *vid);
+                }
+            } else if !self.prev_move_to_closure.contains(vid)
+                && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
+            {
                 self.add_mutably_used_var(*vid);
             }
+            self.prev_bind = None;
+            self.prev_move_to_closure.remove(vid);
         }
     }
 
@@ -265,9 +310,73 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
         self.prev_bind = None;
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(
+        &mut self,
+        cmt: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        _id: HirId,
+    ) {
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if let FakeReadCause::ForLet(Some(inner)) = cause {
+                // Seems like we are inside an async function. We need to store the closure `DefId`
+                // to go through it afterwards.
+                self.async_closures.insert(inner);
+                self.aliases.insert(cmt.hir_id, *vid);
+                self.prev_move_to_closure.insert(*vid);
+            }
+        }
+    }
 
     fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         self.prev_bind = Some(id);
     }
 }
+
+/// A final pass to check for paths referencing this function that require the argument to be
+/// `&mut`, basically if the function is ever used as a `fn`-like argument.
+struct FnNeedsMutVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    used_fn_def_ids: &'a mut FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) {
+        walk_qpath(self, qpath, hir_id);
+
+        let Self { cx, used_fn_def_ids } = self;
+
+        // #11182; do not lint if mutability is required elsewhere
+        if let Node::Expr(expr) = cx.tcx.hir().get(hir_id)
+            && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
+            && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind()
+            && let Some(def_id) = def_id.as_local()
+        {
+            if let Node::Expr(e) = parent
+                && let ExprKind::Call(call, _) = e.kind
+                && call.hir_id == expr.hir_id
+            {
+                return;
+            }
+
+            // We don't need to check each argument individually as you cannot coerce a function
+            // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's
+            // passed as a `fn`-like argument (or is unified) and should ignore every "unused"
+            // argument entirely
+            used_fn_def_ids.insert(def_id);
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 5e26601537f..5ee26966fa7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
-    implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+    implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
 };
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
@@ -182,7 +182,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !ty.is_mutable_ptr();
                 if !is_copy(cx, ty);
                 if ty.is_sized(cx.tcx, cx.param_env);
-                if !allowed_traits.iter().any(|&t| implements_trait_with_env(cx.tcx, cx.param_env, ty, t, [None]));
+                if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter(
+                    cx.tcx,
+                    cx.param_env,
+                    ty,
+                    t,
+                    [Option::<ty::GenericArg<'tcx>>::None],
+                ));
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 8bb2fa92585..a70692d8ff8 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -154,7 +154,7 @@ fn is_value_unfrozen_raw<'tcx>(
             ty::Adt(def, ..) if def.is_union() => false,
             ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
             ty::Adt(def, _) if def.is_union() => false,
-            ty::Adt(def, substs) if def.is_enum() => {
+            ty::Adt(def, args) if def.is_enum() => {
                 let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
                 let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
                 fields
@@ -164,19 +164,14 @@ fn is_value_unfrozen_raw<'tcx>(
                         def.variants()[variant_index]
                             .fields
                             .iter()
-                            .map(|field| field.ty(cx.tcx, substs)),
+                            .map(|field| field.ty(cx.tcx, args)),
                     )
                     .any(|(field, ty)| inner(cx, field, ty))
             },
-            ty::Adt(def, substs) => val
+            ty::Adt(def, args) => val
                 .unwrap_branch()
                 .iter()
-                .zip(
-                    def.non_enum_variant()
-                        .fields
-                        .iter()
-                        .map(|field| field.ty(cx.tcx, substs)),
-                )
+                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
                 .any(|(field, ty)| inner(cx, *field, ty)),
             ty::Tuple(tys) => val
                 .unwrap_branch()
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 35dd8fabe6e..f9108145cdb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,7 +1,7 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::consts::{constant, constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -138,8 +138,10 @@ impl ArithmeticSideEffects {
         ) {
             return;
         };
-        let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
-        let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
+        let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        actual_lhs = expr_or_init(cx, actual_lhs);
+        actual_rhs = expr_or_init(cx, actual_rhs);
         let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
         let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs();
         if self.has_allowed_binary(lhs_ty, rhs_ty) {
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 1fddf0f50e3..c146f3ae95b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -40,9 +40,9 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp
         if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
             return;
         }
-        fetch_int_literal(cx, right)
-            .or_else(|| fetch_int_literal(cx, left))
-            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
+        if let Some(mask) = fetch_int_literal(cx, right).or_else(|| fetch_int_literal(cx, left)) {
+            check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span);
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 377bddeaa5f..9c7f7e1cd7f 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_direct_expn_of;
-use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,21 +35,27 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
 
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if_chain! {
-            if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind;
-            if matches!(seg.ident.name, sym::expect | sym::unwrap);
-            if let ExprKind::Call(caller, _) = &receiver.kind;
-            if is_direct_expn_of(caller.span, "option_env").is_some();
-            then {
-                span_lint_and_help(
-                    cx,
-                    OPTION_ENV_UNWRAP,
-                    expr.span,
-                    "this will panic at run-time if the environment variable doesn't exist at compile-time",
-                    None,
-                    "consider using the `env!` macro instead"
-                );
-            }
+        fn lint(cx: &EarlyContext<'_>, span: Span) {
+            span_lint_and_help(
+                cx,
+                OPTION_ENV_UNWRAP,
+                span,
+                "this will panic at run-time if the environment variable doesn't exist at compile-time",
+                None,
+                "consider using the `env!` macro instead",
+            );
         }
+
+        if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind &&
+		matches!(seg.ident.name, sym::expect | sym::unwrap) {
+			if let ExprKind::Call(caller, _) = &receiver.kind &&
+            // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			} else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			}
+		}
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 264c38df11f..42299d8d42f 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -26,6 +26,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::{fmt, iter};
@@ -163,6 +164,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             }
 
             check_mut_from_ref(cx, sig, None);
+
+            if !matches!(sig.header.abi, Abi::Rust) {
+                // Ignore `extern` functions with non-Rust calling conventions
+                return;
+            }
+
             for arg in check_fn_args(
                 cx,
                 cx.tcx
@@ -222,6 +229,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
         };
 
         check_mut_from_ref(cx, sig, Some(body));
+
+        if !matches!(sig.header.abi, Abi::Rust) {
+            // Ignore `extern` functions with non-Rust calling conventions
+            return;
+        }
+
         let decl = sig.decl;
         let sig = cx.tcx.fn_sig(item_id).instantiate_identity().skip_binder();
         let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params)
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
new file mode 100644
index 00000000000..140ae837a17
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -0,0 +1,103 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::ty::needs_ordered_drop;
+use rustc_hir::def::Res;
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for redundant redefinitions of local bindings.
+    ///
+    /// ### Why is this bad?
+    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    ///
+    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let a = 0;
+    /// let a = a;
+    ///
+    /// fn foo(b: i32) {
+    ///    let b = b;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = 0;
+    /// // no redefinition with the same name
+    ///
+    /// fn foo(b: i32) {
+    ///   // no redefinition with the same name
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_LOCALS,
+    correctness,
+    "redundant redefinition of a local binding"
+}
+declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
+
+impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+        if_chain! {
+            // the pattern is a single by-value binding
+            if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+            // the binding is not type-ascribed
+            if local.ty.is_none();
+            // the expression is a resolved path
+            if let Some(expr) = local.init;
+            if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind;
+            // the path is a single segment equal to the local's name
+            if let [last_segment] = path.segments;
+            if last_segment.ident == ident;
+            // resolve the path to its defining binding pattern
+            if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
+            if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
+            // the previous binding has the same mutability
+            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            // the local does not affect the code's drop behavior
+            if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+            // the local is user-controlled
+            if !in_external_macro(cx.sess(), local.span);
+            if !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_help(
+                    cx,
+                    REDUNDANT_LOCALS,
+                    vec![binding_pat.span, local.span],
+                    "redundant redefinition of a binding",
+                    None,
+                    &format!("remove the redefinition of `{ident}`"),
+                );
+            }
+        }
+    }
+}
+
+/// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
+fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
+    let mut ret = None;
+
+    pat.each_binding_or_first(&mut |annotation, _, _, ident| {
+        if ident == name {
+            ret = Some(annotation);
+        }
+    });
+
+    ret
+}
+
+/// Check if a rebinding of a local affects the code's drop behavior.
+fn affects_drop_behavior<'tcx>(cx: &LateContext<'tcx>, bind: HirId, rebind: HirId, rebind_expr: &Expr<'tcx>) -> bool {
+    let hir = cx.tcx.hir();
+
+    // the rebinding is in a different scope than the original binding
+    // and the type of the binding cares about drop order
+    hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+        && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 038dfe8e480..ed42a422b4b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -5,6 +5,7 @@ use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +65,7 @@ impl RedundantStaticLifetimes {
                 if let Some(lifetime) = *optional_lifetime {
                     match borrow_type.ty.kind {
                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
-                            if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
+                            if lifetime.ident.name == kw::StaticLifetime {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
                                 let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
                                 span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index e532dd61a82..49bdc679604 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     ("clippy::stutter", "clippy::module_name_repetitions"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 2a494ff1fa6..351bacf5691 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,12 +1,14 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
+use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi};
 use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{
+    Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
@@ -76,6 +78,46 @@ declare_clippy_lint! {
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements on `Err` paired with the `?` operator.
+    ///
+    /// ### Why is this bad?
+    /// The `return` is unnecessary.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// if paired with `try_err`, use instead:
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+    style,
+    "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
 #[derive(PartialEq, Eq)]
 enum RetReplacement<'tcx> {
     Empty,
@@ -115,9 +157,35 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
     }
 }
 
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
 
 impl<'tcx> LateLintPass<'tcx> for Return {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if !in_external_macro(cx.sess(), stmt.span)
+            && let StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::Ret(Some(ret)) = expr.kind
+            && let ExprKind::Match(.., MatchSource::TryDesugar) = ret.kind
+            // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+            && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+            && let ItemKind::Fn(_, _, body) = item.kind
+            && let block = cx.tcx.hir().body(body).value
+            && let ExprKind::Block(block, _) = block.kind
+            && let [.., final_stmt] = block.stmts
+            && final_stmt.hir_id != stmt.hir_id
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_RETURN_WITH_QUESTION_MARK,
+                expr.span.until(ret.span),
+                "unneeded `return` statement with `?` operator",
+                "remove it",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
         // we need both a let-binding stmt and an expr
         if_chain! {
@@ -173,6 +241,10 @@ impl<'tcx> LateLintPass<'tcx> for Return {
         sp: Span,
         _: LocalDefId,
     ) {
+        if sp.from_expansion() {
+            return;
+        }
+
         match kind {
             FnKind::Closure => {
                 // when returning without value in closure, replace this `return`
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 355f907e257..c9547cd95dc 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
             if let Some(expr) = block.expr;
             let t_expr = cx.typeck_results().expr_ty(expr);
             if t_expr.is_unit();
-            let mut app = Applicability::MaybeIncorrect;
+            let mut app = Applicability::MachineApplicable;
             if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0;
             if !snippet.ends_with('}') && !snippet.ends_with(';');
             if cx.sess().source_map().is_multiline(block.span);
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 3b282dbfa04..4b248c9c790 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -235,7 +235,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
 
     fn manage_has_expensive_expr_after_last_attr(&mut self) {
         let has_expensive_stmt = match self.ap.curr_stmt.kind {
-            hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false,
+            hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
             hir::StmtKind::Local(local) if let Some(expr) = local.init
                 && let hir::ExprKind::Path(_) = expr.kind => false,
             _ => true
@@ -330,13 +330,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
                             apa.last_method_span = span;
                         }
                     },
-                    hir::StmtKind::Semi(expr) => {
-                        if has_drop(expr, &apa.first_bind_ident, self.cx) {
+                    hir::StmtKind::Semi(semi_expr) => {
+                        if has_drop(semi_expr, &apa.first_bind_ident, self.cx) {
                             apa.has_expensive_expr_after_last_attr = false;
                             apa.last_stmt_span = DUMMY_SP;
                             return;
                         }
-                        if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+                        if let hir::ExprKind::MethodCall(_, _, _, span) = semi_expr.kind {
                             apa.last_method_span = span;
                         }
                     },
@@ -434,16 +434,31 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_
         && let Res::Def(DefKind::Fn, did) = fun_path.res
         && lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
         && let [first_arg, ..] = args
-        && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
-        && let [first_arg_ps, .. ] = arg_path.segments
     {
-        &first_arg_ps.ident == first_bind_ident
-    }
-    else {
-        false
+        let has_ident = |local_expr: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
+                && let [first_arg_ps, .. ] = arg_path.segments
+                && &first_arg_ps.ident == first_bind_ident
+            {
+                true
+            }
+            else {
+                false
+            }
+        };
+        if has_ident(first_arg) {
+            return true;
+        }
+        if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) {
+            return true;
+        }
     }
+    false
 }
 
-fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool {
-    !matches!(expr.kind, hir::ExprKind::Path(_))
+fn is_inexpensive_expr(expr: &hir::Expr<'_>) -> bool {
+    let actual = peel_hir_expr_unary(expr).0;
+    let is_path = matches!(actual.kind, hir::ExprKind::Path(_));
+    let is_lit = matches!(actual.kind, hir::ExprKind::Lit(_));
+    is_path || is_lit
 }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 858135c8d46..54a33eb2986 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
+    get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
+    path_to_local_id, paths, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -60,7 +60,24 @@ struct VecAllocation<'tcx> {
 
     /// Reference to the expression used as argument on `with_capacity` call. This is used
     /// to only match slow zero-filling idioms of the same length than vector initialization.
-    len_expr: &'tcx Expr<'tcx>,
+    size_expr: InitializedSize<'tcx>,
+}
+
+/// Initializer for the creation of the vector.
+///
+/// When `Vec::with_capacity(size)` is found, the `size` expression will be in
+/// `InitializedSize::Initialized`.
+///
+/// Otherwise, for `Vec::new()` calls, there is no allocation initializer yet, so
+/// `InitializedSize::Uninitialized` is used.
+/// Later, when a call to `.resize(size, 0)` or similar is found, it's set
+/// to `InitializedSize::Initialized(size)`.
+///
+/// Since it will be set to `InitializedSize::Initialized(size)` when a slow initialization is
+/// found, it is always safe to "unwrap" it at lint time.
+enum InitializedSize<'tcx> {
+    Initialized(&'tcx Expr<'tcx>),
+    Uninitialized,
 }
 
 /// Type of slow initialization
@@ -77,18 +94,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
         // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
-
-            // Extract variable
             if let Some(local_id) = path_to_local(left);
-
-            // Extract len argument
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, right);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, right);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: right,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, expr.hir_id);
@@ -98,17 +111,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
+        // or `Vec::new()`
         if_chain! {
             if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, init);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: init,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, stmt.hir_id);
@@ -118,19 +132,20 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 }
 
 impl SlowVectorInit {
-    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
-    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
-    fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = expr.kind;
-            if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
-            if name.ident.as_str() == "with_capacity";
-            if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec);
-            then {
-                Some(arg)
-            } else {
-                None
-            }
+    /// Looks for `Vec::with_capacity(size)` or `Vec::new()` calls and returns the initialized size,
+    /// if any. More specifically, it returns:
+    /// - `Some(InitializedSize::Initialized(size))` for `Vec::with_capacity(size)`
+    /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()`
+    /// - `None` for other, unrelated kinds of expressions
+    fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<InitializedSize<'tcx>> {
+        if let ExprKind::Call(func, [len_expr]) = expr.kind
+            && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
+        {
+            Some(InitializedSize::Initialized(len_expr))
+        } else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) {
+            Some(InitializedSize::Uninitialized)
+        } else {
+            None
         }
     }
 
@@ -169,12 +184,19 @@ impl SlowVectorInit {
     }
 
     fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
-        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
+        let len_expr = Sugg::hir(
+            cx,
+            match vec_alloc.size_expr {
+                InitializedSize::Initialized(expr) => expr,
+                InitializedSize::Uninitialized => unreachable!("size expression must be set by this point"),
+            },
+            "len",
+        );
 
         span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
             diag.span_suggestion(
                 vec_alloc.allocation_expr.span,
-                "consider replace allocation with",
+                "consider replacing this with",
                 format!("vec![0; {len_expr}]"),
                 Applicability::Unspecified,
             );
@@ -214,36 +236,45 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     }
 
     /// Checks if the given expression is resizing a vector with 0
-    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
+    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
             && path.ident.name == sym!(resize)
             // Check that is filled with 0
-            && is_integer_literal(fill_arg, 0) {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                }
+            && is_integer_literal(fill_arg, 0)
+        {
+            let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                // If we have a size expression, check that it is equal to what's passed to `resize`
+                SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+            } else {
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                true
+            };
+
+            if is_matching_resize {
+                self.slow_expression = Some(InitializationType::Resize(expr));
             }
+        }
     }
 
     /// Returns `true` if give expression is `repeat(0).take(...)`
-    fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
+    fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
         if_chain! {
             if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
             // Check that take is applied to `repeat(0)`
             if self.is_repeat_zero(recv);
             then {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    return true;
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    return true;
+                if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                    // Check that len expression is equals to `with_capacity` expression
+                    return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                        || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
                 }
+
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                return true;
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 2e00ed042a8..7eec6982092 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -1,21 +1,29 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{is_from_proc_macro, path_to_local};
+use itertools::Itertools;
 use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind, HirId, Node, Pat};
+use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use std::iter::once;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for tuple<=>array conversions that are not done with `.into()`.
     ///
     /// ### Why is this bad?
-    /// It may be unnecessary complexity. `.into()` works for converting tuples
-    /// <=> arrays of up to 12 elements and may convey intent more clearly.
+    /// It may be unnecessary complexity. `.into()` works for converting tuples<=> arrays of up to
+    /// 12 elements and conveys the intent more clearly, while also leaving less room for hard to
+    /// spot bugs!
+    ///
+    /// ### Known issues
+    /// The suggested code may hide potential asymmetry in some cases. See
+    /// [#11085](https://github.com/rust-lang/rust-clippy/issues/11085) for more info.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -29,7 +37,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.72.0"]
     pub TUPLE_ARRAY_CONVERSIONS,
-    pedantic,
+    nursery,
     "checks for tuple<=>array conversions that are not done with `.into()`"
 }
 impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
@@ -41,130 +49,152 @@ pub struct TupleArrayConversions {
 
 impl LateLintPass<'_> for TupleArrayConversions {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !in_external_macro(cx.sess(), expr.span) && self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
-            match expr.kind {
-                ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
-                ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
-                _ => {},
-            }
+        if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+            return;
+        }
+
+        match expr.kind {
+            ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
+            ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
+            _ => {},
         }
     }
 
     extract_msrv_attr!(LateContext);
 }
 
-#[expect(
-    clippy::blocks_in_if_conditions,
-    reason = "not a FP, but this is much easier to understand"
-)]
 fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
-    if should_lint(
-        cx,
-        elements,
-        // This is cursed.
-        Some,
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Tuple(len) if len.len() == elements.len()
-                );
-            }
-
-            false
-        },
-    ) || should_lint(
-        cx,
-        elements,
-        |(i, expr)| {
-            if let ExprKind::Field(path, field) = expr.kind && field.as_str() == i.to_string() {
-                return Some((i, path));
-            };
-
-            None
-        },
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Tuple(len) if len.len() == elements.len()
-                );
-            }
+    let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else {
+        unreachable!("`expr` must be an array or slice due to `ExprKind::Array`");
+    };
+
+    if let [first, ..] = elements
+        && let Some(locals) = (match first.kind {
+            ExprKind::Field(_, _) => elements
+                .iter()
+                .enumerate()
+                .map(|(i, f)| -> Option<&'tcx Expr<'tcx>> {
+                    let ExprKind::Field(lhs, ident) = f.kind else {
+                        return None;
+                    };
+                    (ident.name.as_str() == i.to_string()).then_some(lhs)
+                })
+                .collect::<Option<Vec<_>>>(),
+            ExprKind::Path(_) => Some(elements.iter().collect()),
+            _ => None,
+        })
+        && all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array)
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_help(
+            cx,
+            TUPLE_ARRAY_CONVERSIONS,
+            expr.span,
+            "it looks like you're trying to convert a tuple to an array",
+            None,
+            "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
+        );
+    }
+}
 
-            false
-        },
-    ) {
-        emit_lint(cx, expr, ToType::Array);
+fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
+    if let ty::Tuple(tys) = cx.typeck_results().expr_ty(expr).kind()
+        && let [first, ..] = elements
+        // Fix #11100
+        && tys.iter().all_equal()
+        && let Some(locals) = (match first.kind {
+            ExprKind::Index(_, _) => elements
+                .iter()
+                .enumerate()
+                .map(|(i, i_expr)| -> Option<&'tcx Expr<'tcx>> {
+                    if let ExprKind::Index(lhs, index) = i_expr.kind
+                        && let ExprKind::Lit(lit) = index.kind
+                        && let LitKind::Int(val, _) = lit.node
+                    {
+                        return (val == i as u128).then_some(lhs);
+                    };
+
+                    None
+                })
+                .collect::<Option<Vec<_>>>(),
+            ExprKind::Path(_) => Some(elements.iter().collect()),
+            _ => None,
+        })
+        && all_bindings_are_for_conv(cx, tys, expr, elements, &locals, ToType::Tuple)
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_help(
+            cx,
+            TUPLE_ARRAY_CONVERSIONS,
+            expr.span,
+            "it looks like you're trying to convert an array to a tuple",
+            None,
+            "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+        );
     }
 }
 
-#[expect(
-    clippy::blocks_in_if_conditions,
-    reason = "not a FP, but this is much easier to understand"
-)]
+/// Checks that every binding in `elements` comes from the same parent `Pat` with the kind if there
+/// is a parent `Pat`. Returns false in any of the following cases:
+/// * `kind` does not match `pat.kind`
+/// * one or more elements in `elements` is not a binding
+/// * one or more bindings does not have the same parent `Pat`
+/// * one or more bindings are used after `expr`
+/// * the bindings do not all have the same type
 #[expect(clippy::cast_possible_truncation)]
-fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
-    if should_lint(cx, elements, Some, |(first_id, local)| {
-        if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
-                );
+fn all_bindings_are_for_conv<'tcx>(
+    cx: &LateContext<'tcx>,
+    final_tys: &[Ty<'tcx>],
+    expr: &Expr<'_>,
+    elements: &[Expr<'_>],
+    locals: &[&Expr<'_>],
+    kind: ToType,
+) -> bool {
+    let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
+        return false;
+    };
+    let Some(local_parents) = locals
+        .iter()
+        .map(|&l| cx.tcx.hir().find_parent(l))
+        .collect::<Option<Vec<_>>>()
+    else {
+        return false;
+    };
+
+    local_parents
+        .iter()
+        .map(|node| match node {
+            Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id),
+            Node::Local(l) => Some(l.hir_id),
+            _ => None,
+        })
+        .all_equal()
+        // Fix #11124, very convenient utils function! ❤️
+        && locals
+            .iter()
+            .all(|&l| for_each_local_use_after_expr(cx, l, expr.hir_id, |_| ControlFlow::Break::<()>(())).is_continue())
+        && local_parents.first().is_some_and(|node| {
+            let Some(ty) = match node {
+                Node::Pat(pat) => Some(pat.hir_id),
+                Node::Local(l) => Some(l.hir_id),
+                _ => None,
             }
-
-        false
-    }) || should_lint(
-        cx,
-        elements,
-        |(i, expr)| {
-            if let ExprKind::Index(path, index) = expr.kind
-                && let ExprKind::Lit(lit) = index.kind
-                && let LitKind::Int(val, _) = lit.node
-                && val as usize == i
-            {
-                return Some((i, path));
+            .map(|hir_id| cx.typeck_results().node_type(hir_id)) else {
+                return false;
             };
-
-            None
-        },
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
-                );
+            match (kind, ty.kind()) {
+                // Ensure the final type and the original type have the same length, and that there
+                // is no implicit `&mut`<=>`&` anywhere (#11100). Bit ugly, I know, but it works.
+                (ToType::Array, ty::Tuple(tys)) => {
+                    tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal()
+                },
+                (ToType::Tuple, ty::Array(ty, len)) => {
+                    len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
+                        && final_tys.iter().chain(once(ty)).all_equal()
+                },
+                _ => false,
             }
-
-            false
-        },
-    ) {
-        emit_lint(cx, expr, ToType::Tuple);
-    }
-}
-
-/// Walks up the `Pat` until it's reached the final containing `Pat`.
-fn parent_pat<'tcx>(cx: &LateContext<'tcx>, start: &'tcx Pat<'tcx>) -> &'tcx Pat<'tcx> {
-    let mut end = start;
-    for (_, node) in cx.tcx.hir().parent_iter(start.hir_id) {
-        if let Node::Pat(pat) = node {
-            end = pat;
-        } else {
-            break;
-        }
-    }
-    end
+        })
 }
 
 #[derive(Clone, Copy)]
@@ -173,61 +203,11 @@ enum ToType {
     Tuple,
 }
 
-impl ToType {
-    fn msg(self) -> &'static str {
-        match self {
-            ToType::Array => "it looks like you're trying to convert a tuple to an array",
-            ToType::Tuple => "it looks like you're trying to convert an array to a tuple",
-        }
-    }
-
-    fn help(self) -> &'static str {
+impl PartialEq<PatKind<'_>> for ToType {
+    fn eq(&self, other: &PatKind<'_>) -> bool {
         match self {
-            ToType::Array => "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
-            ToType::Tuple => "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+            ToType::Array => matches!(other, PatKind::Tuple(_, _)),
+            ToType::Tuple => matches!(other, PatKind::Slice(_, _, _)),
         }
     }
 }
-
-fn emit_lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, to_type: ToType) -> bool {
-    if !is_from_proc_macro(cx, expr) {
-        span_lint_and_help(
-            cx,
-            TUPLE_ARRAY_CONVERSIONS,
-            expr.span,
-            to_type.msg(),
-            None,
-            to_type.help(),
-        );
-
-        return true;
-    }
-
-    false
-}
-
-fn should_lint<'tcx>(
-    cx: &LateContext<'tcx>,
-    elements: &'tcx [Expr<'tcx>],
-    map: impl FnMut((usize, &'tcx Expr<'tcx>)) -> Option<(usize, &Expr<'_>)>,
-    predicate: impl FnMut((HirId, &Node<'tcx>)) -> bool,
-) -> bool {
-    if let Some(elements) = elements
-            .iter()
-            .enumerate()
-            .map(map)
-            .collect::<Option<Vec<_>>>()
-        && let Some(locals) = elements
-            .iter()
-            .map(|(_, element)| path_to_local(element).and_then(|local| cx.tcx.hir().find(local)))
-            .collect::<Option<Vec<_>>>()
-        && let [first, rest @ ..] = &*locals
-        && let Node::Pat(first_pat) = first
-        && let parent = parent_pat(cx, first_pat).hir_id
-        && rest.iter().chain(once(first)).map(|i| (parent, i)).all(predicate)
-    {
-        return true;
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 5e42cf7e4f3..bc7c3897a6e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,11 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_def_id_trait_method;
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::def_id::LocalDefId;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::{LocalDefId, LocalDefIdSet};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -38,7 +39,24 @@ declare_clippy_lint! {
     "finds async functions with no await statements"
 }
 
-declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+#[derive(Default)]
+pub struct UnusedAsync {
+    /// Keeps track of async functions used as values (i.e. path expressions to async functions that
+    /// are not immediately called)
+    async_fns_as_value: LocalDefIdSet,
+    /// Functions with unused `async`, linted post-crate after we've found all uses of local async
+    /// functions
+    unused_async_fns: Vec<UnusedAsyncFn>,
+}
+
+#[derive(Copy, Clone)]
+struct UnusedAsyncFn {
+    def_id: LocalDefId,
+    fn_span: Span,
+    await_in_async_block: Option<Span>,
+}
+
+impl_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
 
 struct AsyncFnVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
@@ -101,24 +119,70 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
-                span_lint_and_then(
-                    cx,
-                    UNUSED_ASYNC,
-                    span,
-                    "unused `async` for function with no await statements",
-                    |diag| {
-                        diag.help("consider removing the `async` from this function");
-
-                        if let Some(span) = visitor.await_in_async_block {
-                            diag.span_note(
-                                span,
-                                "`await` used in an async block, which does not require \
-                                the enclosing function to be `async`",
-                            );
-                        }
-                    },
-                );
+                // Don't lint just yet, but store the necessary information for later.
+                // The actual linting happens in `check_crate_post`, once we've found all
+                // uses of local async functions that do require asyncness to pass typeck
+                self.unused_async_fns.push(UnusedAsyncFn {
+                    await_in_async_block: visitor.await_in_async_block,
+                    fn_span: span,
+                    def_id,
+                });
             }
         }
     }
+
+    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
+        fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
+            matches!(
+                node,
+                Node::Expr(Expr {
+                    kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
+                    ..
+                }) if *span == expected_receiver
+            )
+        }
+
+        // Find paths to local async functions that aren't immediately called.
+        // E.g. `async fn f() {}; let x = f;`
+        // Depending on how `x` is used, f's asyncness might be required despite not having any `await`
+        // statements, so don't lint at all if there are any such paths.
+        if let Some(def_id) = path.res.opt_def_id()
+            && let Some(local_def_id) = def_id.as_local()
+            && let Some(DefKind::Fn) = cx.tcx.opt_def_kind(def_id)
+            && cx.tcx.asyncness(def_id).is_async()
+            && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
+        {
+            self.async_fns_as_value.insert(local_def_id);
+        }
+    }
+
+    // After collecting all unused `async` and problematic paths to such functions,
+    // lint those unused ones that didn't have any path expressions to them.
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        let iter = self
+            .unused_async_fns
+            .iter()
+            .filter(|UnusedAsyncFn { def_id, .. }| (!self.async_fns_as_value.contains(def_id)));
+
+        for fun in iter {
+            span_lint_hir_and_then(
+                cx,
+                UNUSED_ASYNC,
+                cx.tcx.local_def_id_to_hir_id(fun.def_id),
+                fun.fn_span,
+                "unused `async` for function with no await statements",
+                |diag| {
+                    diag.help("consider removing the `async` from this function");
+
+                    if let Some(span) = fun.await_in_async_block {
+                        diag.span_note(
+                            span,
+                            "`await` used in an async block, which does not require \
+                            the enclosing function to be `async`",
+                        );
+                    }
+                },
+            );
+        }
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 76654bfe536..58ae0656db7 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -551,6 +551,16 @@ define_Conf! {
     ///
     /// Whether to allow `r#""#` when `r""` can be used
     (allow_one_hash_in_raw_strings: bool = false),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// The maximum number of segments a path can have before being linted, anything above this will
+    /// be linted.
+    (absolute_paths_max_segments: u64 = 2),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// Which crates to allow absolute paths from
+    (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
+        rustc_data_structures::fx::FxHashSet::default()),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index fb08256931f..4fef8c0717d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -18,7 +18,7 @@ const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configura
 // ==================================================================
 // Configuration
 // ==================================================================
-#[derive(Debug, Clone, Default)] //~ ERROR no such field
+#[derive(Debug, Clone, Default)]
 pub struct ClippyConfiguration {
     pub name: String,
     #[allow(dead_code)]
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 357ac40b455..802adbd4d2d 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -138,6 +138,7 @@ impl<'hir> IfLet<'hir> {
 }
 
 /// An `if let` or `match` expression. Useful for lints that trigger on one or the other.
+#[derive(Debug)]
 pub enum IfLetOrMatch<'hir> {
     /// Any `match` expression
     Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index fb359ee3bbe..85b3b005f93 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -252,15 +252,15 @@ impl HirEqInterExpr<'_, '_, '_> {
             return false;
         }
 
-        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
-            if let (Some(l), Some(r)) = (
+        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
+            && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
+            && let (Some(l), Some(r)) = (
                 constant_simple(self.inner.cx, typeck_lhs, left),
                 constant_simple(self.inner.cx, typeck_rhs, right),
-            ) {
-                if l == r {
-                    return true;
-                }
-            }
+            )
+            && l == r
+        {
+            return true;
         }
 
         let is_eq = match (
@@ -494,10 +494,13 @@ impl HirEqInterExpr<'_, '_, '_> {
             loop {
                 use TokenKind::{BlockComment, LineComment, Whitespace};
                 if left_data.macro_def_id != right_data.macro_def_id
-                    || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg)
-                        && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
-                            !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
-                        }))
+                    || (matches!(
+                        left_data.kind,
+                        ExpnKind::Macro(MacroKind::Bang, name)
+                        if name == sym::cfg || name == sym::option_env
+                    ) && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
+                        !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
+                    }))
                 {
                     // Either a different chain of macro calls, or different arguments to the `cfg` macro.
                     return false;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 45b99df46b0..cf30930b76e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -89,21 +89,21 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
-    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
-    MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
+    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item,
+    ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+    QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::ConstantKind;
-use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
+    TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -113,7 +113,10 @@ use rustc_target::abi::Integer;
 
 use crate::consts::{constant, miri_to_const, Constant};
 use crate::higher::Range;
-use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
+use crate::ty::{
+    adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
+    ty_is_fn_once_param,
+};
 use crate::visitors::for_each_expr;
 
 use rustc_middle::hir::nested_filter;
@@ -2445,6 +2448,17 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
         .any(is_cfg_test)
 }
 
+/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
+pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let hir = tcx.hir();
+
+    tcx.has_attr(def_id, sym::cfg)
+        || hir
+            .parent_iter(hir.local_def_id_to_hir_id(def_id))
+            .flat_map(|(parent_id, _)| hir.attrs(parent_id))
+            .any(|attr| attr.has_name(sym::cfg))
+}
+
 /// Checks whether item either has `test` attribute applied, or
 /// is a module with `test` in its name.
 ///
@@ -2499,6 +2513,262 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// A type definition as it would be viewed from within a function.
+#[derive(Clone, Copy)]
+pub enum DefinedTy<'tcx> {
+    // Used for locals and closures defined within the function.
+    Hir(&'tcx hir::Ty<'tcx>),
+    /// Used for function signatures, and constant and static values. This includes the `ParamEnv`
+    /// from the definition site.
+    Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>),
+}
+
+/// The context an expressions value is used in.
+pub struct ExprUseCtxt<'tcx> {
+    /// The parent node which consumes the value.
+    pub node: ExprUseNode<'tcx>,
+    /// Any adjustments applied to the type.
+    pub adjustments: &'tcx [Adjustment<'tcx>],
+    /// Whether or not the type must unify with another code path.
+    pub is_ty_unified: bool,
+    /// Whether or not the value will be moved before it's used.
+    pub moved_before_use: bool,
+}
+
+/// The node which consumes a value.
+pub enum ExprUseNode<'tcx> {
+    /// Assignment to, or initializer for, a local
+    Local(&'tcx Local<'tcx>),
+    /// Initializer for a const or static item.
+    ConstStatic(OwnerId),
+    /// Implicit or explicit return from a function.
+    Return(OwnerId),
+    /// Initialization of a struct field.
+    Field(&'tcx ExprField<'tcx>),
+    /// An argument to a function.
+    FnArg(&'tcx Expr<'tcx>, usize),
+    /// An argument to a method.
+    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
+    /// The callee of a function call.
+    Callee,
+    /// Access of a field.
+    FieldAccess(Ident),
+}
+impl<'tcx> ExprUseNode<'tcx> {
+    /// Checks if the value is returned from the function.
+    pub fn is_return(&self) -> bool {
+        matches!(self, Self::Return(_))
+    }
+
+    /// Checks if the value is used as a method call receiver.
+    pub fn is_recv(&self) -> bool {
+        matches!(self, Self::MethodArg(_, _, 0))
+    }
+
+    /// Gets the needed type as it's defined without any type inference.
+    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
+        match *self {
+            Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+            Self::ConstStatic(id) => Some(DefinedTy::Mir(
+                cx.param_env
+                    .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
+            )),
+            Self::Return(id) => {
+                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(id.def_id);
+                if let Some(Node::Expr(Expr {
+                    kind: ExprKind::Closure(c),
+                    ..
+                })) = cx.tcx.hir().find(hir_id)
+                {
+                    match c.fn_decl.output {
+                        FnRetTy::DefaultReturn(_) => None,
+                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
+                    }
+                } else {
+                    Some(DefinedTy::Mir(
+                        cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()),
+                    ))
+                }
+            },
+            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
+                Some(Expr {
+                    hir_id,
+                    kind: ExprKind::Struct(path, ..),
+                    ..
+                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+                    .and_then(|(adt, variant)| {
+                        variant
+                            .fields
+                            .iter()
+                            .find(|f| f.name == field.ident.name)
+                            .map(|f| (adt, f))
+                    })
+                    .map(|(adt, field_def)| {
+                        DefinedTy::Mir(
+                            cx.tcx
+                                .param_env(adt.did())
+                                .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())),
+                        )
+                    }),
+                _ => None,
+            },
+            Self::FnArg(callee, i) => {
+                let sig = expr_sig(cx, callee)?;
+                let (hir_ty, ty) = sig.input_with_hir(i)?;
+                Some(match hir_ty {
+                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
+                    None => DefinedTy::Mir(
+                        sig.predicates_id()
+                            .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id))
+                            .and(ty),
+                    ),
+                })
+            },
+            Self::MethodArg(id, _, i) => {
+                let id = cx.typeck_results().type_dependent_def_id(id)?;
+                let sig = cx.tcx.fn_sig(id).skip_binder();
+                Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
+            },
+            Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+        }
+    }
+}
+
+/// Gets the context an expression's value is used in.
+#[expect(clippy::too_many_lines)]
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
+    let mut adjustments = [].as_slice();
+    let mut is_ty_unified = false;
+    let mut moved_before_use = false;
+    let ctxt = e.span.ctxt();
+    walk_to_expr_usage(cx, e, &mut |parent, child_id| {
+        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
+            adjustments = cx.typeck_results().expr_adjustments(e);
+        }
+        match parent {
+            Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Local(l),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+            Node::Item(&Item {
+                kind: ItemKind::Static(..) | ItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::ConstStatic(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Item(&Item {
+                kind: ItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Return(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Field(field),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
+                ExprKind::Ret(_) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId {
+                        def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+                    }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Closure(closure) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Call(func, args) => Some(ExprUseCtxt {
+                    node: match args.iter().position(|arg| arg.hir_id == child_id) {
+                        Some(i) => ExprUseNode::FnArg(func, i),
+                        None => ExprUseNode::Callee,
+                    },
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
+                    node: ExprUseNode::MethodArg(
+                        parent.hir_id,
+                        name.args,
+                        args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+                    ),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
+                    node: ExprUseNode::FieldAccess(name),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(..) => {
+                    moved_before_use = true;
+                    None
+                },
+                _ => None,
+            },
+            _ => None,
+        }
+    })
+}
+
 /// Tokenizes the input while keeping the text associated with each token.
 pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
     let mut pos = 0;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index 8e7513d740a..da04266863f 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
         let lhs = place.local;
         match rvalue {
             // Only consider `&mut`, which can modify origin place
-            mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+            mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, borrowed) |
             // _2: &mut _;
             // _3 = move _2
             mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index f3677e6f614..914ea85ac28 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -149,6 +149,7 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
 pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
@@ -161,3 +162,6 @@ pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
 pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
 pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
 pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
+pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
+#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
+pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index fd39a246f48..d0e15aa8bb3 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::module_name_repetitions)]
 
 use core::ops::ControlFlow;
+use itertools::Itertools;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -13,21 +14,26 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, IntTy,
-    List, ParamEnv, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-    UintTy, VariantDef, VariantDiscr,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Size, VariantIdx};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::iter;
 
 use crate::{match_def_path, path_res, paths};
 
+mod type_certainty;
+pub use type_certainty::expr_type_is_certain;
+
 /// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
@@ -204,15 +210,9 @@ pub fn implements_trait<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: &[GenericArg<'tcx>],
+    args: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env(
-        cx.tcx,
-        cx.param_env,
-        ty,
-        trait_id,
-        ty_params.iter().map(|&arg| Some(arg)),
-    )
+    implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -221,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>(
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
+    args: &[GenericArg<'tcx>],
+) -> bool {
+    implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
+}
+
+/// Same as `implements_trait_from_env` but takes the arguments as an iterator.
+pub fn implements_trait_with_env_from_iter<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    trait_id: DefId,
+    args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
 ) -> bool {
     // Clippy shouldn't have infer types
     assert!(!ty.has_infer());
@@ -230,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
     if ty.has_escaping_bound_vars() {
         return false;
     }
+
     let infcx = tcx.infer_ctxt().build();
-    let orig = TypeVariableOrigin {
-        kind: TypeVariableOriginKind::MiscVariable,
-        span: DUMMY_SP,
-    };
-    let ty_params = tcx.mk_args_from_iter(
-        ty_params
+    let trait_ref = TraitRef::new(
+        tcx,
+        trait_id,
+        Some(GenericArg::from(ty))
             .into_iter()
-            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+            .chain(args.into_iter().map(|arg| {
+                arg.into().unwrap_or_else(|| {
+                    let orig = TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::MiscVariable,
+                        span: DUMMY_SP,
+                    };
+                    infcx.next_ty_var(orig).into()
+                })
+            })),
     );
+
+    debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait);
+    #[cfg(debug_assertions)]
+    assert_generic_args_match(tcx, trait_id, trait_ref.args);
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+    };
     infcx
-        .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
-        .must_apply_modulo_regions()
+        .evaluate_obligation(&obligation)
+        .is_ok_and(EvaluationResult::must_apply_modulo_regions)
 }
 
 /// Checks whether this type implements `Drop`.
@@ -390,6 +419,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
     }
 }
 
+/// Gets the diagnostic name of the type, if it has one
+pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
+    ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did()))
+}
+
 /// Return `true` if the passed `typ` is `isize` or `usize`.
 pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
@@ -739,7 +773,11 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
     let mut output = None;
     let lang_items = cx.tcx.lang_items();
 
-    for (pred, _) in cx.tcx.explicit_item_bounds(ty.def_id).iter_instantiated_copied(cx.tcx, ty.args) {
+    for (pred, _) in cx
+        .tcx
+        .explicit_item_bounds(ty.def_id)
+        .iter_instantiated_copied(cx.tcx, ty.args)
+    {
         match pred.kind().skip_binder() {
             ty::ClauseKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
@@ -1007,12 +1045,60 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
     }
 }
 
+/// Asserts that the given arguments match the generic parameters of the given item.
+#[allow(dead_code)]
+fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
+    let g = tcx.generics_of(did);
+    let parent = g.parent.map(|did| tcx.generics_of(did));
+    let count = g.parent_count + g.params.len();
+    let params = parent
+        .map_or([].as_slice(), |p| p.params.as_slice())
+        .iter()
+        .chain(&g.params)
+        .map(|x| &x.kind);
+
+    assert!(
+        count == args.len(),
+        "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\
+            note: the expected arguments are: `[{}]`\n\
+            the given arguments are: `{args:#?}`",
+        args.len(),
+        params.clone().map(GenericParamDefKind::descr).format(", "),
+    );
+
+    if let Some((idx, (param, arg))) =
+        params
+            .clone()
+            .zip(args.iter().map(|&x| x.unpack()))
+            .enumerate()
+            .find(|(_, (param, arg))| match (param, arg) {
+                (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+                | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+                | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
+                (
+                    GenericParamDefKind::Lifetime
+                    | GenericParamDefKind::Type { .. }
+                    | GenericParamDefKind::Const { .. },
+                    _,
+                ) => true,
+            })
+    {
+        panic!(
+            "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n\
+                note: the expected arguments are `[{}]`\n\
+                the given arguments are `{args:#?}`",
+            param.descr(),
+            params.clone().map(GenericParamDefKind::descr).format(", "),
+        );
+    }
+}
+
 /// Makes the projection type for the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to exist, and as such, will only return
 /// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
 /// enabled this will check that the named associated type exists, the correct number of
-/// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
+/// arguments are given, and that the correct kinds of arguments are given (lifetime,
 /// constant or type). This will not check if type normalization would succeed.
 pub fn make_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -1036,49 +1122,7 @@ pub fn make_projection<'tcx>(
             return None;
         };
         #[cfg(debug_assertions)]
-        {
-            let generics = tcx.generics_of(assoc_item.def_id);
-            let generic_count = generics.parent_count + generics.params.len();
-            let params = generics
-                .parent
-                .map_or([].as_slice(), |id| &*tcx.generics_of(id).params)
-                .iter()
-                .chain(&generics.params)
-                .map(|x| &x.kind);
-
-            debug_assert!(
-                generic_count == args.len(),
-                "wrong number of args for `{:?}`: found `{}` expected `{generic_count}`.\n\
-                    note: the expected parameters are: {:#?}\n\
-                    the given arguments are: `{args:#?}`",
-                assoc_item.def_id,
-                args.len(),
-                params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
-            );
-
-            if let Some((idx, (param, arg))) = params
-                .clone()
-                .zip(args.iter().map(GenericArg::unpack))
-                .enumerate()
-                .find(|(_, (param, arg))| {
-                    !matches!(
-                        (param, arg),
-                        (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
-                            | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
-                            | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
-                    )
-                })
-            {
-                debug_assert!(
-                    false,
-                    "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
-                        note: the expected parameters are {:#?}\n\
-                        the given arguments are {args:#?}",
-                    param.descr(),
-                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
-                );
-            }
-        }
+        assert_generic_args_match(tcx, assoc_item.def_id, args);
 
         Some(tcx.mk_alias_ty(assoc_item.def_id, args))
     }
@@ -1093,7 +1137,7 @@ pub fn make_projection<'tcx>(
 /// Normalizes the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to be valid with the given
-/// substitutions, and as such, will only return `None` when debug assertions are disabled in order
+/// arguments, and as such, will only return `None` when debug assertions are disabled in order
 /// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
@@ -1105,17 +1149,12 @@ pub fn make_normalized_projection<'tcx>(
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .args
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
                 "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
@@ -1183,17 +1222,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .args
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
                 "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
new file mode 100644
index 00000000000..0e69ffa2212
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
@@ -0,0 +1,122 @@
+use rustc_hir::def_id::DefId;
+use std::fmt::Debug;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Certainty {
+    /// Determining the type requires contextual information.
+    Uncertain,
+
+    /// The type can be determined purely from subexpressions. If the argument is `Some(..)`, the
+    /// specific `DefId` is known. Such arguments are needed to handle path segments whose `res` is
+    /// `Res::Err`.
+    Certain(Option<DefId>),
+
+    /// The heuristic believes that more than one `DefId` applies to a type---this is a bug.
+    Contradiction,
+}
+
+pub trait Meet {
+    fn meet(self, other: Self) -> Self;
+}
+
+pub trait TryJoin: Sized {
+    fn try_join(self, other: Self) -> Option<Self>;
+}
+
+impl Meet for Option<DefId> {
+    fn meet(self, other: Self) -> Self {
+        match (self, other) {
+            (None, _) | (_, None) => None,
+            (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(lhs),
+        }
+    }
+}
+
+impl TryJoin for Option<DefId> {
+    fn try_join(self, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(Some(lhs)),
+            (Some(def_id), _) | (_, Some(def_id)) => Some(Some(def_id)),
+            (None, None) => Some(None),
+        }
+    }
+}
+
+impl Meet for Certainty {
+    fn meet(self, other: Self) -> Self {
+        match (self, other) {
+            (Certainty::Uncertain, _) | (_, Certainty::Uncertain) => Certainty::Uncertain,
+            (Certainty::Certain(lhs), Certainty::Certain(rhs)) => Certainty::Certain(lhs.meet(rhs)),
+            (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+            (Certainty::Contradiction, Certainty::Contradiction) => Certainty::Contradiction,
+        }
+    }
+}
+
+impl Certainty {
+    /// Join two `Certainty`s preserving their `DefId`s (if any). Generally speaking, this method
+    /// should be used only when `self` and `other` refer directly to types. Otherwise,
+    /// `join_clearing_def_ids` should be used.
+    pub fn join(self, other: Self) -> Self {
+        match (self, other) {
+            (Certainty::Contradiction, _) | (_, Certainty::Contradiction) => Certainty::Contradiction,
+
+            (Certainty::Certain(lhs), Certainty::Certain(rhs)) => {
+                if let Some(inner) = lhs.try_join(rhs) {
+                    Certainty::Certain(inner)
+                } else {
+                    debug_assert!(false, "Contradiction with {lhs:?} and {rhs:?}");
+                    Certainty::Contradiction
+                }
+            },
+
+            (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+
+            (Certainty::Uncertain, Certainty::Uncertain) => Certainty::Uncertain,
+        }
+    }
+
+    /// Join two `Certainty`s after clearing their `DefId`s. This method should be used when `self`
+    /// or `other` do not necessarily refer to types, e.g., when they are aggregations of other
+    /// `Certainty`s.
+    pub fn join_clearing_def_ids(self, other: Self) -> Self {
+        self.clear_def_id().join(other.clear_def_id())
+    }
+
+    pub fn clear_def_id(self) -> Certainty {
+        if matches!(self, Certainty::Certain(_)) {
+            Certainty::Certain(None)
+        } else {
+            self
+        }
+    }
+
+    pub fn with_def_id(self, def_id: DefId) -> Certainty {
+        if matches!(self, Certainty::Certain(_)) {
+            Certainty::Certain(Some(def_id))
+        } else {
+            self
+        }
+    }
+
+    pub fn to_def_id(self) -> Option<DefId> {
+        match self {
+            Certainty::Certain(inner) => inner,
+            _ => None,
+        }
+    }
+
+    pub fn is_certain(self) -> bool {
+        matches!(self, Self::Certain(_))
+    }
+}
+
+/// Think: `iter.all(/* is certain */)`
+pub fn meet(iter: impl Iterator<Item = Certainty>) -> Certainty {
+    iter.fold(Certainty::Certain(None), Certainty::meet)
+}
+
+/// Think: `iter.any(/* is certain */)`
+pub fn join(iter: impl Iterator<Item = Certainty>) -> Certainty {
+    iter.fold(Certainty::Uncertain, Certainty::join)
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
new file mode 100644
index 00000000000..45b5483e323
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -0,0 +1,320 @@
+//! A heuristic to tell whether an expression's type can be determined purely from its
+//! subexpressions, and the arguments and locals they use. Put another way, `expr_type_is_certain`
+//! tries to tell whether an expression's type can be determined without appeal to the surrounding
+//! context.
+//!
+//! This is, in some sense, a counterpart to `let_unit_value`'s `expr_needs_inferred_result`.
+//! Intuitively, that function determines whether an expression's type is needed for type inference,
+//! whereas `expr_type_is_certain` determines whether type inference is needed for an expression's
+//! type.
+//!
+//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
+//! be considered a bug.
+
+use crate::def_path_res;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor};
+use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
+use rustc_span::{Span, Symbol};
+
+mod certainty;
+use certainty::{join, meet, Certainty, Meet};
+
+pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    expr_type_certainty(cx, expr).is_certain()
+}
+
+fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
+    let certainty = match &expr.kind {
+        ExprKind::Unary(_, expr)
+        | ExprKind::Field(expr, _)
+        | ExprKind::Index(expr, _)
+        | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
+
+        ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+        ExprKind::Call(callee, args) => {
+            let lhs = expr_type_certainty(cx, callee);
+            let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+                meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
+            } else {
+                Certainty::Uncertain
+            };
+            lhs.join_clearing_def_ids(rhs)
+        },
+
+        ExprKind::MethodCall(method, receiver, args, _) => {
+            let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
+            // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
+            // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
+            // for example. So update the `DefId` in `receiver_type_certainty` (if any).
+            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                && let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id))
+            {
+                receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id);
+            };
+            let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
+            let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+                meet(
+                    std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
+                )
+            } else {
+                Certainty::Uncertain
+            };
+            lhs.join(rhs)
+        },
+
+        ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+        ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
+
+        ExprKind::Lit(_) => Certainty::Certain(None),
+
+        ExprKind::Cast(_, ty) => type_certainty(cx, ty),
+
+        ExprKind::If(_, if_expr, Some(else_expr)) => {
+            expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
+        },
+
+        ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
+
+        ExprKind::Struct(qpath, _, _) => qpath_certainty(cx, qpath, true),
+
+        _ => Certainty::Uncertain,
+    };
+
+    let expr_ty = cx.typeck_results().expr_ty(expr);
+    if let Some(def_id) = adt_def_id(expr_ty) {
+        certainty.with_def_id(def_id)
+    } else {
+        certainty
+    }
+}
+
+struct CertaintyVisitor<'cx, 'tcx> {
+    cx: &'cx LateContext<'tcx>,
+    certainty: Certainty,
+}
+
+impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> {
+    fn new(cx: &'cx LateContext<'tcx>) -> Self {
+        Self {
+            cx,
+            certainty: Certainty::Certain(None),
+        }
+    }
+}
+
+impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> {
+    fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
+        self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true));
+        if self.certainty != Certainty::Uncertain {
+            walk_qpath(self, qpath, hir_id);
+        }
+    }
+
+    fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) {
+        if matches!(ty.kind, TyKind::Infer) {
+            self.certainty = Certainty::Uncertain;
+        }
+        if self.certainty != Certainty::Uncertain {
+            walk_ty(self, ty);
+        }
+    }
+}
+
+fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
+    // Handle `TyKind::Path` specially so that its `DefId` can be preserved.
+    //
+    // Note that `CertaintyVisitor::new` initializes the visitor's internal certainty to
+    // `Certainty::Certain(None)`. Furthermore, if a `TyKind::Path` is encountered while traversing
+    // `ty`, the result of the call to `qpath_certainty` is combined with the visitor's internal
+    // certainty using `Certainty::meet`. Thus, if the `TyKind::Path` were not treated specially here,
+    // the resulting certainty would be `Certainty::Certain(None)`.
+    if let TyKind::Path(qpath) = &ty.kind {
+        return qpath_certainty(cx, qpath, true);
+    }
+
+    let mut visitor = CertaintyVisitor::new(cx);
+    visitor.visit_ty(ty);
+    visitor.certainty
+}
+
+fn generic_args_certainty(cx: &LateContext<'_>, args: &GenericArgs<'_>) -> Certainty {
+    let mut visitor = CertaintyVisitor::new(cx);
+    visitor.visit_generic_args(args);
+    visitor.certainty
+}
+
+/// Tries to tell whether a `QPath` resolves to something certain, e.g., whether all of its path
+/// segments generic arguments are are instantiated.
+///
+/// `qpath` could refer to either a type or a value. The heuristic never needs the `DefId` of a
+/// value. So `DefId`s are retained only when `resolves_to_type` is true.
+fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bool) -> Certainty {
+    let certainty = match qpath {
+        QPath::Resolved(ty, path) => {
+            let len = path.segments.len();
+            path.segments.iter().enumerate().fold(
+                ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)),
+                |parent_certainty, (i, path_segment)| {
+                    path_segment_certainty(cx, parent_certainty, path_segment, i != len - 1 || resolves_to_type)
+                },
+            )
+        },
+
+        QPath::TypeRelative(ty, path_segment) => {
+            path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type)
+        },
+
+        QPath::LangItem(lang_item, _, _) => {
+            cx.tcx
+                .lang_items()
+                .get(*lang_item)
+                .map_or(Certainty::Uncertain, |def_id| {
+                    let generics = cx.tcx.generics_of(def_id);
+                    if generics.parent_count == 0 && generics.params.is_empty() {
+                        Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
+                    } else {
+                        Certainty::Uncertain
+                    }
+                })
+        },
+    };
+    debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+    certainty
+}
+
+fn path_segment_certainty(
+    cx: &LateContext<'_>,
+    parent_certainty: Certainty,
+    path_segment: &PathSegment<'_>,
+    resolves_to_type: bool,
+) -> Certainty {
+    let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) {
+        // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or
+        // an unparameterized type), or the generics are instantiated with arguments that are certain.
+        //
+        // If the parent is uncertain, then the current path segment must account for the parent's generic arguments.
+        // Consider the following examples, where the current path segment is `None`:
+        // - `Option::None`             // uncertain; parent (i.e., `Option`) is uncertain
+        // - `Option::<Vec<u64>>::None` // certain; parent (i.e., `Option::<..>`) is certain
+        // - `Option::None::<Vec<u64>>` // certain; parent (i.e., `Option`) is uncertain
+        Res::Def(_, def_id) => {
+            // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
+            if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
+                let generics = cx.tcx.generics_of(def_id);
+                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty()
+                {
+                    Certainty::Certain(None)
+                } else {
+                    Certainty::Uncertain
+                };
+                let rhs = path_segment
+                    .args
+                    .map_or(Certainty::Uncertain, |args| generic_args_certainty(cx, args));
+                // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value.
+                let certainty = lhs.join_clearing_def_ids(rhs);
+                if resolves_to_type {
+                    if cx.tcx.def_kind(def_id) == DefKind::TyAlias {
+                        adt_def_id(cx.tcx.type_of(def_id).instantiate_identity())
+                            .map_or(certainty, |def_id| certainty.with_def_id(def_id))
+                    } else {
+                        certainty.with_def_id(def_id)
+                    }
+                } else {
+                    certainty
+                }
+            } else {
+                Certainty::Certain(None)
+            }
+        },
+
+        Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) => {
+            Certainty::Certain(None)
+        },
+
+        // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
+        Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) {
+            // An argument's type is always certain.
+            Node::Param(..) => Certainty::Certain(None),
+            // A local's type is certain if its type annotation is certain or it has an initializer whose
+            // type is certain.
+            Node::Local(local) => {
+                let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
+                let rhs = local
+                    .init
+                    .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
+                let certainty = lhs.join(rhs);
+                if resolves_to_type {
+                    certainty
+                } else {
+                    certainty.clear_def_id()
+                }
+            },
+            _ => Certainty::Uncertain,
+        },
+
+        _ => Certainty::Uncertain,
+    };
+    debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+    certainty
+}
+
+/// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`.
+/// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`.
+fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> {
+    if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() {
+        let mut def_path = cx.get_def_path(def_id);
+        def_path.push(path_segment.ident.name);
+        let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>());
+        if let [res] = reses.as_slice() { Some(*res) } else { None }
+    } else {
+        None
+    }
+}
+
+#[allow(clippy::cast_possible_truncation)]
+fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let Some(callee_def_id) = (match expr.kind {
+        ExprKind::Call(callee, _) => {
+            let callee_ty = cx.typeck_results().expr_ty(callee);
+            if let ty::FnDef(callee_def_id, _) = callee_ty.kind() {
+                Some(*callee_def_id)
+            } else {
+                None
+            }
+        },
+        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
+        _ => None,
+    }) else {
+        return false;
+    };
+
+    let generics = cx.tcx.generics_of(callee_def_id);
+    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+
+    // Check that all type parameters appear in the functions input types.
+    (0..(generics.parent_count + generics.params.len()) as u32).all(|index| {
+        fn_sig
+            .inputs()
+            .iter()
+            .any(|input_ty| contains_param(*input_ty.skip_binder(), index))
+    })
+}
+
+fn self_ty<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId) -> Ty<'tcx> {
+    cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()[0]
+}
+
+fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
+    ty.peel_refs().ty_adt_def().map(AdtDef::did)
+}
+
+fn contains_param(ty: Ty<'_>, index: u32) -> bool {
+    ty.walk()
+        .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index)))
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 20993398d1b..39ef76348d7 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,14 +1,15 @@
-use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend};
+use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
+use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
 use core::ops::ControlFlow;
+use hir::def::Res;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Node};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
-use {crate as utils, rustc_hir as hir};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -127,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
     }
 
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
-        if let hir::def::Res::Local(id) = path.res {
+        if let Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
             }
@@ -153,6 +154,17 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
     .is_some()
 }
 
+pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
+    for_each_expr_with_closures(cx, v, |e| {
+        if utils::path_to_local_id(e, local_id) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
+
 pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
     let Some(block) = utils::get_enclosing_block(cx, local_id) else {
         return false;
@@ -165,32 +177,21 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
     // let closure = || local;
     // closure();
     // closure();
-    let in_loop_or_closure = cx
-        .tcx
-        .hir()
-        .parent_iter(after.hir_id)
-        .take_while(|&(id, _)| id != block.hir_id)
-        .any(|(_, node)| {
-            matches!(
-                node,
-                Node::Expr(Expr {
-                    kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
-                    ..
-                })
-            )
-        });
-    if in_loop_or_closure {
-        return true;
-    }
+    let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
 
     let mut past_expr = false;
     for_each_expr_with_closures(cx, block, |e| {
-        if e.hir_id == after.hir_id {
+        if past_expr {
+            if utils::path_to_local_id(e, local_id) {
+                ControlFlow::Break(())
+            } else {
+                ControlFlow::Continue(Descend::Yes)
+            }
+        } else if e.hir_id == after.hir_id {
             past_expr = true;
             ControlFlow::Continue(Descend::No)
-        } else if past_expr && utils::path_to_local_id(e, local_id) {
-            ControlFlow::Break(())
         } else {
+            past_expr = Some(e.hir_id) == loop_start;
             ControlFlow::Continue(Descend::Yes)
         }
     })
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 8dafa723afa..09f447b27eb 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -52,6 +52,16 @@ pub trait Visitable<'tcx> {
     /// Calls the corresponding `visit_*` function on the visitor.
     fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
+impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
+where
+    &'tcx T: Visitable<'tcx>,
+{
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+        for x in self {
+            x.visit(visitor);
+        }
+    }
+}
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
         impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index b658101a10d..833608faff0 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-07-14"
+channel = "nightly-2023-07-28"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index ee17feed77a..1d89477dcc1 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -192,7 +192,7 @@ You can use tool lints to allow or deny lints from your code, eg.:
     );
 }
 
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
 
 #[allow(clippy::too_many_lines)]
 pub fn main() {
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index cdc85cb33ca..26b655076cf 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -132,8 +132,7 @@ impl ClippyCmd {
         let clippy_args: String = self
             .clippy_args
             .iter()
-            .map(|arg| format!("{arg}__CLIPPY_HACKERY__"))
-            .collect();
+            .fold(String::new(), |s, arg| s + arg + "__CLIPPY_HACKERY__");
 
         // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
         let terminal_width = termize::dimensions().map_or(0, |(w, _)| w);
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f714b296233..385e25ce6b8 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -5,7 +5,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
-use compiletest::{status_emitter, CommandBuilder};
+use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling};
 use ui_test as compiletest;
 use ui_test::Mode as TestMode;
 
@@ -115,12 +115,12 @@ fn base_config(test_dir: &str) -> compiletest::Config {
         mode: TestMode::Yolo,
         stderr_filters: vec![],
         stdout_filters: vec![],
-        // FIXME(tgross35): deduplicate bless env once clippy can update
         output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0")
-        || env::args().any(|arg| arg == "--bless") {
-            compiletest::OutputConflictHandling::Bless
+            || env::args().any(|arg| arg == "--bless")
+        {
+            OutputConflictHandling::Bless
         } else {
-            compiletest::OutputConflictHandling::Error("cargo test -- -- --bless".into())
+            OutputConflictHandling::Error("cargo uibless".into())
         },
         target: None,
         out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"),
@@ -189,9 +189,6 @@ fn run_ui() {
                 .to_string()
         }),
     );
-    eprintln!("   Compiler: {}", config.program.display());
-
-    let name = config.root_dir.display().to_string();
 
     let test_filter = test_filter();
 
@@ -199,7 +196,7 @@ fn run_ui() {
         config,
         move |path| compiletest::default_file_filter(path) && test_filter(path),
         compiletest::default_per_file_config,
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
     check_rustfix_coverage();
@@ -210,8 +207,19 @@ fn run_internal_tests() {
     if !RUN_INTERNAL_TESTS {
         return;
     }
-    let config = base_config("ui-internal");
-    compiletest::run_tests(config).unwrap();
+    let mut config = base_config("ui-internal");
+    if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
+        *err = "cargo uitest --features internal -- -- --bless".into();
+    }
+    let test_filter = test_filter();
+
+    compiletest::run_tests_generic(
+        config,
+        move |path| compiletest::default_file_filter(path) && test_filter(path),
+        compiletest::default_per_file_config,
+        status_emitter::Text,
+    )
+    .unwrap();
 }
 
 fn run_ui_toml() {
@@ -230,13 +238,11 @@ fn run_ui_toml() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
         config,
-        |path| test_filter(path) && path.extension() == Some("rs".as_ref()),
+        |path| compiletest::default_file_filter(path) && test_filter(path),
         |config, path| {
             let mut config = config.clone();
             config
@@ -245,7 +251,7 @@ fn run_ui_toml() {
                 .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
@@ -286,8 +292,6 @@ fn run_ui_cargo() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
@@ -298,7 +302,7 @@ fn run_ui_cargo() {
             config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap());
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index a771d8b87c8..031982edbe9 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -65,6 +65,30 @@ fn integration_test() {
         .expect("unable to run clippy");
 
     let stderr = String::from_utf8_lossy(&output.stderr);
+
+    // debug:
+    eprintln!("{stderr}");
+
+    // this is an internal test to make sure we would correctly panic on a delay_span_bug
+    if repo_name == "matthiaskrgr/clippy_ci_panic_test" {
+        // we need to kind of switch around our logic here:
+        // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing
+
+        // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic:
+        /*
+           #![feature(rustc_attrs)]
+           #[rustc_error(delay_span_bug_from_inside_query)]
+           fn main() {}
+        */
+
+        if stderr.find("error: internal compiler error").is_some() {
+            eprintln!("we saw that we intentionally panicked, yay");
+            return;
+        }
+
+        panic!("panic caused by delay_span_bug was NOT detected! Something is broken!");
+    }
+
     if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
         static BACKTRACE_END_MSG: &str = "end of query stack";
         let backtrace_end = stderr[backtrace_start..]
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
index 4dd9582aff8..74e40c09ebc 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
 #![warn(clippy::redundant_feature_names)]
 #![warn(clippy::negative_feature_names)]
 
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
index 4dd9582aff8..74e40c09ebc 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
 #![warn(clippy::redundant_feature_names)]
 #![warn(clippy::negative_feature_names)]
 
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
index c70d92e359e..ac21b3a4422 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
@@ -1,3 +1,4 @@
+// FIXME: find a way to add rustflags to ui-cargo tests
 //@compile-flags: --remap-path-prefix {{src-base}}=/remapped
 
 #![warn(clippy::self_named_module_files)]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
index bb3a39d0720..3491ccb0d47 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
 #![warn(clippy::wildcard_dependencies)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
index bb3a39d0720..3491ccb0d47 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
 #![warn(clippy::wildcard_dependencies)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b88aeae2a9b..31df0ebd9fd 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -3,7 +3,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: the compiler unexpectedly panicked. this is a bug.
 
-note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
+note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
 
 note: rustc <version> running on <target>
 
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
new file mode 100644
index 00000000000..a8900da4e6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
@@ -0,0 +1,28 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
new file mode 100644
index 00000000000..41b70644be8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
@@ -0,0 +1,70 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:43:5
+   |
+LL |     crate::a::b::c::C;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:44:5
+   |
+LL |     crate::a::b::c::d::e::f::F;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:45:5
+   |
+LL |     crate::a::A;
+   |     ^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:46:5
+   |
+LL |     crate::a::b::B;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:47:5
+   |
+LL |     crate::a::b::c::C::ZERO;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:48:5
+   |
+LL |     helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:49:5
+   |
+LL |     ::helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
new file mode 100644
index 00000000000..d4c250a8ff2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
@@ -0,0 +1,97 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
+//@aux-build:helper.rs
+//@revisions: allow_crates disallow_crates
+//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates
+//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::absolute_paths)]
+#![feature(decl_macro)]
+
+extern crate helper;
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+    pub mod b {
+        pub mod c {
+            pub struct C;
+
+            impl C {
+                pub const ZERO: u32 = 0;
+            }
+
+            pub mod d {
+                pub mod e {
+                    pub mod f {
+                        pub struct F;
+                    }
+                }
+            }
+        }
+
+        pub struct B;
+    }
+
+    pub struct A;
+}
+
+fn main() {
+    f32::max(1.0, 2.0);
+    std::f32::MAX;
+    core::f32::MAX;
+    ::core::f32::MAX;
+    crate::a::b::c::C;
+    crate::a::b::c::d::e::f::F;
+    crate::a::A;
+    crate::a::b::B;
+    crate::a::b::c::C::ZERO;
+    helper::b::c::d::e::f();
+    ::helper::b::c::d::e::f();
+    fn b() -> a::b::B {
+        todo!()
+    }
+    std::println!("a");
+    let x = 1;
+    std::ptr::addr_of!(x);
+    // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it
+    // has 3
+    ::std::f32::MAX;
+    // Do not lint due to the above
+    ::helper::a();
+    // Do not lint
+    helper::a();
+    use crate::a::b::c::C;
+    use a::b;
+    use std::f32::MAX;
+    a::b::c::d::e::f::F;
+    b::c::C;
+    fn a() -> a::A {
+        todo!()
+    }
+    use a::b::c;
+
+    fn c() -> c::C {
+        todo!()
+    }
+    fn d() -> Result<(), ()> {
+        todo!()
+    }
+    external! {
+        crate::a::b::c::C::ZERO;
+    }
+    // For some reason, `path.span.from_expansion()` takes care of this for us
+    with_span! {
+        span
+        crate::a::b::c::C::ZERO;
+    }
+    macro_rules! local_crate {
+        () => {
+            crate::a::b::c::C::ZERO;
+        };
+    }
+    macro local_crate_2_0() {
+        crate::a::b::c::C::ZERO;
+    }
+    local_crate!();
+    local_crate_2_0!();
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
new file mode 100644
index 00000000000..59a621e9d1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
@@ -0,0 +1,2 @@
+absolute-paths-max-segments = 2
+absolute-paths-allowed-crates = ["crate", "helper"]
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
new file mode 100644
index 00000000000..8e2678f5fe6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
@@ -0,0 +1,11 @@
+pub fn a() {}
+
+pub mod b {
+    pub mod c {
+        pub mod d {
+            pub mod e {
+                pub fn f() {}
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
new file mode 100644
index 00000000000..d44d648c641
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
@@ -0,0 +1 @@
+absolute-paths-max-segments = 2
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6ba26e97730..cdabe6460cd 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,6 @@
 error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
@@ -68,6 +70,8 @@ LL | foobar = 42
    | ^^^^^^
 
 error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
index b6fcca0a791..2940c273255 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
@@ -1,6 +1,12 @@
+//@aux-build:proc_macros.rs:proc-macro
 #![warn(clippy::arc_with_non_send_sync)]
 #![allow(unused_variables)]
+
+#[macro_use]
+extern crate proc_macros;
+
 use std::cell::RefCell;
+use std::ptr::{null, null_mut};
 use std::sync::{Arc, Mutex};
 
 fn foo<T>(x: T) {
@@ -11,14 +17,32 @@ fn issue11076<T>() {
     let a: Arc<Vec<T>> = Arc::new(Vec::new());
 }
 
+fn issue11232() {
+    external! {
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+    with_span! {
+        span
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+}
+
 fn main() {
     let _ = Arc::new(42);
 
-    // !Sync
     let _ = Arc::new(RefCell::new(42));
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Sync` is not implemented for `RefCell<i32>`
+
     let mutex = Mutex::new(1);
-    // !Send
     let _ = Arc::new(mutex.lock().unwrap());
-    // !Send + !Sync
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+
     let _ = Arc::new(&42 as *const i32);
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `*const i32`
+    //~| NOTE: the trait `Sync` is not implemented for `*const i32`
 }
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
index 7633b38dfb5..de3f2fb9e16 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
@@ -1,5 +1,5 @@
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:18:13
+  --> $DIR/arc_with_non_send_sync.rs:35:13
    |
 LL |     let _ = Arc::new(RefCell::new(42));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |     let _ = Arc::new(RefCell::new(42));
    = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:21:13
+  --> $DIR/arc_with_non_send_sync.rs:40:13
    |
 LL |     let _ = Arc::new(mutex.lock().unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     let _ = Arc::new(mutex.lock().unwrap());
    = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:23:13
+  --> $DIR/arc_with_non_send_sync.rs:44:13
    |
 LL |     let _ = Arc::new(&42 as *const i32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index ed75acee8a2..2ac2fa22086 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -486,4 +486,11 @@ pub fn issue_11145() {
     x += 1;
 }
 
+pub fn issue_11262() {
+    let one = 1;
+    let zero = 0;
+    let _ = 2 / one;
+    let _ = 2 / zero;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
index c92dd509ebb..af219eed0b8 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v.is_empty();
     let _ = !v.is_empty();
+    if (*v).is_empty() {}
+    let s = [0].as_slice();
+    if s.is_empty() {}
+    if s.is_empty() {}
+    if s.is_empty() && s.is_empty() {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
index b3489714380..21e65184d50 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.rs
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v == [];
     let _ = v != [];
+    if let [] = &*v {}
+    let s = [0].as_slice();
+    if let [] = s {}
+    if let [] = &*s {}
+    if let [] = &*s && s == [] {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
index cc09b17eb89..f29782ed80d 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:9:13
+  --> $DIR/comparison_to_empty.rs:10:13
    |
 LL |     let _ = s == "";
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -7,22 +7,52 @@ LL |     let _ = s == "";
    = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:10:13
+  --> $DIR/comparison_to_empty.rs:11:13
    |
 LL |     let _ = s != "";
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:13:13
+  --> $DIR/comparison_to_empty.rs:14:13
    |
 LL |     let _ = v == [];
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:14:13
+  --> $DIR/comparison_to_empty.rs:15:13
    |
 LL |     let _ = v != [];
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
 
-error: aborting due to 4 previous errors
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:16:8
+   |
+LL |     if let [] = &*v {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:18:8
+   |
+LL |     if let [] = s {}
+   |        ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:19:8
+   |
+LL |     if let [] = &*s {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:20:8
+   |
+LL |     if let [] = &*s && s == [] {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:20:24
+   |
+LL |     if let [] = &*s && s == [] {}
+   |                        ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/error_impl_error.rs b/src/tools/clippy/tests/ui/error_impl_error.rs
new file mode 100644
index 00000000000..40ce4181bf3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.rs
@@ -0,0 +1,90 @@
+#![allow(unused)]
+#![warn(clippy::error_impl_error)]
+#![no_main]
+
+pub mod a {
+    #[derive(Debug)]
+    pub struct Error;
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod b {
+    #[derive(Debug)]
+    pub(super) enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod c {
+    pub union Error {
+        a: u32,
+        b: u32,
+    }
+
+    impl std::fmt::Debug for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod d {
+    pub type Error = std::fmt::Error;
+}
+
+mod e {
+    #[derive(Debug)]
+    pub(super) struct MyError;
+
+    impl std::fmt::Display for MyError {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for MyError {}
+}
+
+pub mod f {
+    pub type MyError = std::fmt::Error;
+}
+
+// Do not lint module-private types
+
+mod g {
+    #[derive(Debug)]
+    enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod h {
+    type Error = std::fmt::Error;
+}
diff --git a/src/tools/clippy/tests/ui/error_impl_error.stderr b/src/tools/clippy/tests/ui/error_impl_error.stderr
new file mode 100644
index 00000000000..f3e04b64167
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.stderr
@@ -0,0 +1,45 @@
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:7:16
+   |
+LL |     pub struct Error;
+   |                ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:15:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::error-impl-error` implied by `-D warnings`
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:20:21
+   |
+LL |     pub(super) enum Error {}
+   |                     ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:28:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:32:15
+   |
+LL |     pub union Error {
+   |               ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:49:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type alias named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:53:14
+   |
+LL |     pub type Error = std::fmt::Error;
+   |              ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index db7bd99e0ae..ddabe7616d0 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -345,3 +345,58 @@ fn angle_brackets_and_args() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(<dyn TestTrait>::method_on_dyn);
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, f2);
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 52fc17686fd..92ecff6eb1a 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -345,3 +345,58 @@ fn angle_brackets_and_args() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(|d| d.method_on_dyn());
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, |x, y| f2(x, y));
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 0ac0b901df4..ff40a2074e5 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -158,5 +158,11 @@ error: redundant closure
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
-error: aborting due to 26 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:389:19
+   |
+LL |     let _ = f(&0, |x, y| f2(x, y));
+   |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
new file mode 100644
index 00000000000..3e72fee4b07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1);
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
new file mode 100644
index 00000000000..38a04e57de4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone()
+        .into_iter()
+        .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
new file mode 100644
index 00000000000..b411cd83dfd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
@@ -0,0 +1,34 @@
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:19:22
+   |
+LL |     v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+   |
+   = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:20:27
+   |
+LL |     v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:23:10
+   |
+LL |         .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:27:10
+   |
+LL |         .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:31:10
+   |
+LL |         .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format_collect.rs b/src/tools/clippy/tests/ui/format_collect.rs
new file mode 100644
index 00000000000..c7f2b7b6950
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.rs
@@ -0,0 +1,31 @@
+#![allow(unused, dead_code)]
+#![warn(clippy::format_collect)]
+
+fn hex_encode(bytes: &[u8]) -> String {
+    bytes.iter().map(|b| format!("{b:02X}")).collect()
+}
+
+#[rustfmt::skip]
+fn hex_encode_deep(bytes: &[u8]) -> String {
+    bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+}
+
+macro_rules! fmt {
+    ($x:ident) => {
+        format!("{x:02X}", x = $x)
+    };
+}
+
+fn from_macro(bytes: &[u8]) -> String {
+    bytes.iter().map(|x| fmt!(x)).collect()
+}
+
+fn with_block() -> String {
+    (1..10)
+        .map(|s| {
+            let y = 1;
+            format!("{s} {y}")
+        })
+        .collect()
+}
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/format_collect.stderr b/src/tools/clippy/tests/ui/format_collect.stderr
new file mode 100644
index 00000000000..d918f1ed466
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.stderr
@@ -0,0 +1,62 @@
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:5:5
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:5:18
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |                  ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:5:26
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |                          ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+   = note: `-D clippy::format-collect` implied by `-D warnings`
+
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:10:5
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:10:18
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |                  ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:10:32
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |                                ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:24:5
+   |
+LL | /     (1..10)
+LL | |         .map(|s| {
+LL | |             let y = 1;
+LL | |             format!("{s} {y}")
+LL | |         })
+LL | |         .collect()
+   | |__________________^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:25:10
+   |
+LL |         .map(|s| {
+   |          ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:27:13
+   |
+LL |             format!("{s} {y}")
+   |             ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.fixed b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
new file mode 100644
index 00000000000..54b2c414b62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+/// whoops
+fn a() {}
+
+/// whoops
+#[allow(dead_code)]
+fn b() {}
+
+/// whoops
+/// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+/// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+/// not very start of contents
+fn h() {}
+
+fn i() {
+    //// don't lint me bozo
+    todo!()
+}
+
+external! {
+    //// don't lint me bozo
+    fn e() {}
+}
+
+with_span! {
+    span
+    //// don't lint me bozo
+    fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.rs b/src/tools/clippy/tests/ui/four_forward_slashes.rs
new file mode 100644
index 00000000000..facdc8cb17d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.rs
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+//// whoops
+fn a() {}
+
+//// whoops
+#[allow(dead_code)]
+fn b() {}
+
+//// whoops
+//// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+//// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+    //// not very start of contents
+fn h() {}
+
+fn i() {
+    //// don't lint me bozo
+    todo!()
+}
+
+external! {
+    //// don't lint me bozo
+    fn e() {}
+}
+
+with_span! {
+    span
+    //// don't lint me bozo
+    fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
new file mode 100644
index 00000000000..89162e6b010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
@@ -0,0 +1,68 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:12:1
+   |
+LL | / //// whoops
+LL | | fn a() {}
+   | |_
+   |
+   = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+   |
+LL + /// whoops
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:15:1
+   |
+LL | / //// whoops
+LL | | #[allow(dead_code)]
+LL | | fn b() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// whoops
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:19:1
+   |
+LL | / //// whoops
+LL | | //// two borked comments!
+LL | | #[track_caller]
+LL | | fn c() {}
+   | |_
+   |
+help: turn these into doc comments by removing one `/`
+   |
+LL + /// whoops
+LL ~ /// two borked comments!
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:27:1
+   |
+LL | / //// between attributes
+LL | | #[allow(dead_code)]
+LL | | fn g() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// between attributes
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:31:1
+   |
+LL | /     //// not very start of contents
+LL | | fn h() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// not very start of contents
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
new file mode 100644
index 00000000000..ce272b4c6cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
@@ -0,0 +1,7 @@
+/// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
new file mode 100644
index 00000000000..d8f82d4410b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
@@ -0,0 +1,7 @@
+//// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
new file mode 100644
index 00000000000..7944da14feb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
@@ -0,0 +1,15 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes_first_line.rs:1:1
+   |
+LL | / //// borked doc comment on the first line. doesn't combust!
+LL | | fn a() {}
+   | |_
+   |
+   = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+   |
+LL + /// borked doc comment on the first line. doesn't combust!
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index dad4543f84c..e84b20e9fef 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -214,4 +214,45 @@ mod issue_8836 {
     }
 }
 
+mod issue_11213 {
+    fn reproducer(x: bool) -> bool {
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u16.is_power_of_two()
+        }
+    }
+
+    // a more obvious reproducer that shows
+    // why the code above is problematic:
+    fn v2(x: bool) -> bool {
+        trait Helper {
+            fn is_u8(&self) -> bool;
+        }
+        impl Helper for u8 {
+            fn is_u8(&self) -> bool {
+                true
+            }
+        }
+        impl Helper for u16 {
+            fn is_u8(&self) -> bool {
+                false
+            }
+        }
+
+        // this is certainly not the same code in both branches
+        // it returns a different bool depending on the branch.
+        if x { 0_u8.is_u8() } else { 0_u16.is_u8() }
+    }
+
+    fn do_lint(x: bool) -> bool {
+        // but do lint if the type of the literal is the same
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u8.is_power_of_two()
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
index a34fc565590..774cc08685a 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -108,5 +108,23 @@ LL | |         bar + 1;
 LL | |     }
    | |_____^
 
-error: aborting due to 5 previous errors
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:250:14
+   |
+LL |           if x {
+   |  ______________^
+LL | |             0_u8.is_power_of_two()
+LL | |         } else {
+   | |_________^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:252:16
+   |
+LL |           } else {
+   |  ________________^
+LL | |             0_u8.is_power_of_two()
+LL | |         }
+   | |_________^
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 5c338e3c5c8..ad77346b75f 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -46,6 +46,10 @@ fn ifs_same_cond() {
         // ok, functions
     } else if v.len() == 42 {
     }
+
+    if let Some(env1) = option_env!("ENV1") {
+    } else if let Some(env2) = option_env!("ENV2") {
+    }
 }
 
 fn issue10272() {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index 8d70934476c..3f52c10b762 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -36,13 +36,13 @@ LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
 
 error: this `if` has the same condition as a previous `if`
-  --> $DIR/ifs_same_cond.rs:54:15
+  --> $DIR/ifs_same_cond.rs:58:15
    |
 LL |     } else if a.contains("ah") {
    |               ^^^^^^^^^^^^^^^^
    |
 note: same as this
-  --> $DIR/ifs_same_cond.rs:53:8
+  --> $DIR/ifs_same_cond.rs:57:8
    |
 LL |     if a.contains("ah") {
    |        ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
index dd4fdd98822..2f51bf27480 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -112,3 +111,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
index 522e82299c0..47127bdaec2 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -116,3 +115,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
index 0e477798c40..66048fc9000 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
@@ -1,5 +1,5 @@
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:18:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1
    |
 LL | /  impl PartialOrd for A {
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -13,7 +13,7 @@ LL | |  }
    = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
 
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:52:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1
    |
 LL | / impl PartialOrd for C {
 LL | |     fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
new file mode 100644
index 00000000000..3a3b84f93c4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
@@ -0,0 +1,51 @@
+// This test's filename is... a bit verbose. But it ensures we suggest the correct code when `Ord`
+// is not in scope.
+#![no_main]
+#![no_implicit_prelude]
+
+extern crate std;
+
+use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd};
+use std::option::Option::{self, Some};
+use std::todo;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl cmp::Ord for A {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for A {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+        // automatically applied
+        todo!();
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl cmp::Ord for B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for B {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // This calls `B.cmp`, not `Ord::cmp`!
+        Some(self.cmp(other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
new file mode 100644
index 00000000000..f4374c28128
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
@@ -0,0 +1,31 @@
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:23:1
+   |
+LL | /  impl PartialOrd for A {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+LL | ||         // automatically applied
+LL | ||         todo!();
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | |  }
+   | |__^
+   |
+   = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:46:1
+   |
+LL | /  impl PartialOrd for B {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // This calls `B.cmp`, not `Ord::cmp`!
+LL | ||         Some(self.cmp(other))
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(std::cmp::Ord::cmp(self, other)) }`
+LL | |  }
+   | |__^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
index 701b3cd1904..04559f9ada4 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/infinite_loop.rs:7:17
-   |
-LL | fn fn_mutref(i: &mut i32) {
-   |                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: variables in the condition are not mutated in the loop body
   --> $DIR/infinite_loop.rs:20:11
    |
@@ -99,5 +91,13 @@ LL |     while y < 10 {
    = note: this loop contains `return`s or `break`s
    = help: rewrite it as `if cond { loop { } }`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/infinite_loop.rs:7:17
+   |
+LL | fn fn_mutref(i: &mut i32) {
+   |                 ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs
index aeb0a0c1e2e..adb0389a043 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.rs
+++ b/src/tools/clippy/tests/ui/inherent_to_string.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::inherent_to_string)]
-#![deny(clippy::inherent_to_string_shadow_display)]
+#![allow(improper_ctypes_definitions)]
 
 use std::fmt;
 
@@ -14,6 +13,9 @@ struct D;
 struct E;
 struct F;
 struct G;
+struct H;
+struct I;
+struct J;
 
 impl A {
     // Should be detected; emit warning
@@ -80,6 +82,26 @@ impl G {
     }
 }
 
+// Issue #11201
+
+impl H {
+    unsafe fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl I {
+    extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl J {
+    unsafe extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
 fn main() {
     let a = A;
     a.to_string();
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr
index 443fecae1aa..579b3c8c56f 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.stderr
+++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr
@@ -1,5 +1,5 @@
 error: implementation of inherent method `to_string(&self) -> String` for type `A`
-  --> $DIR/inherent_to_string.rs:20:5
+  --> $DIR/inherent_to_string.rs:22:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "A.to_string()".to_string()
@@ -10,7 +10,7 @@ LL | |     }
    = note: `-D clippy::inherent-to-string` implied by `-D warnings`
 
 error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
-  --> $DIR/inherent_to_string.rs:44:5
+  --> $DIR/inherent_to_string.rs:46:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "C.to_string()".to_string()
@@ -18,11 +18,7 @@ LL | |     }
    | |_____^
    |
    = help: remove the inherent method from type `C`
-note: the lint level is defined here
-  --> $DIR/inherent_to_string.rs:2:9
-   |
-LL | #![deny(clippy::inherent_to_string_shadow_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::inherent_to_string_shadow_display)]` on by default
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.fixed b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
new file mode 100644
index 00000000000..1eb0984fe07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    let _ = once([1, 2, 3]).skip(1);
+    let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1);
+    // Don't lint
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    external! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+    with_span! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.rs b/src/tools/clippy/tests/ui/iter_skip_zero.rs
new file mode 100644
index 00000000000..8c103ab1d5b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.rs
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+    let _ = [1, 2, 3].iter().skip(0);
+    let _ = vec![1, 2, 3].iter().skip(0);
+    let _ = once([1, 2, 3]).skip(0);
+    let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+    // Don't lint
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    external! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+    with_span! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.stderr b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
new file mode 100644
index 00000000000..80fecd59e6d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
@@ -0,0 +1,43 @@
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:12:35
+   |
+LL |     let _ = [1, 2, 3].iter().skip(0);
+   |                                   ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+   = note: `-D clippy::iter-skip-zero` implied by `-D warnings`
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:13:39
+   |
+LL |     let _ = vec![1, 2, 3].iter().skip(0);
+   |                                       ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:14:34
+   |
+LL |     let _ = once([1, 2, 3]).skip(0);
+   |                                  ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:15:71
+   |
+LL |     let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+   |                                                                       ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:15:62
+   |
+LL |     let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+   |                                                              ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
index 7e4d783a026..64665cc906f 100644
--- a/src/tools/clippy/tests/ui/let_and_return.rs
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -169,4 +169,14 @@ mod issue_5729 {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/11167
+macro_rules! fn_in_macro {
+    ($b:block) => {
+        fn f() -> usize $b
+    }
+}
+fn_in_macro!({
+    return 1;
+});
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_underscore_future.stderr b/src/tools/clippy/tests/ui/let_underscore_future.stderr
index 9e69fb04133..ff1e2b8c901 100644
--- a/src/tools/clippy/tests/ui/let_underscore_future.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_future.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/let_underscore_future.rs:11:35
-   |
-LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: non-binding `let` on a future
   --> $DIR/let_underscore_future.rs:14:5
    |
@@ -31,5 +23,13 @@ LL |     let _ = future;
    |
    = help: consider awaiting the future or dropping explicitly with `std::mem::drop`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/let_underscore_future.rs:11:35
+   |
+LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed
index 9dd376df2b4..35872a39a71 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed
@@ -120,3 +120,27 @@ fn issue_8920() {
         .iter()
         .filter_map(|f| f.result_field.to_owned().ok());
 }
+
+fn issue8010() {
+    #[derive(Clone)]
+    enum Enum {
+        A(i32),
+        B,
+    }
+
+    let iter = [Enum::A(123), Enum::B].into_iter();
+
+    let _x = iter.clone().filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+    let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter
+        .clone()
+        .filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+    #[allow(clippy::unused_unit)]
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::B))
+        .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs
index 6dd1e066aeb..50d8d2722c2 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.rs
+++ b/src/tools/clippy/tests/ui/manual_filter_map.rs
@@ -133,3 +133,31 @@ fn issue_8920() {
         .filter(|f| f.result_field.is_ok())
         .map(|f| f.result_field.to_owned().unwrap());
 }
+
+fn issue8010() {
+    #[derive(Clone)]
+    enum Enum {
+        A(i32),
+        B,
+    }
+
+    let iter = [Enum::A(123), Enum::B].into_iter();
+
+    let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::A(_)))
+        .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+    #[allow(clippy::unused_unit)]
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::B))
+        .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr
index 882468b0f5f..0e8672c0293 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr
@@ -4,6 +4,11 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
 LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
    |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:9:30
+   |
+LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+   |                              ^^^^^^^^^^
    = note: `-D clippy::manual-filter-map` implied by `-D warnings`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
@@ -11,12 +16,24 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
    |
 LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:12:31
+   |
+LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+   |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:15:19
    |
 LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:15:31
+   |
+LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+   |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:18:10
@@ -25,6 +42,12 @@ LL |           .filter(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:18:22
+   |
+LL |         .filter(|&x| to_ref(to_opt(x)).is_some())
+   |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:21:10
@@ -33,6 +56,12 @@ LL |           .filter(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:21:21
+   |
+LL |         .filter(|x| to_ref(to_opt(*x)).is_some())
+   |                     ^^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:25:10
@@ -41,6 +70,12 @@ LL |           .filter(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:25:22
+   |
+LL |         .filter(|&x| to_ref(to_res(x)).is_ok())
+   |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:28:10
@@ -49,6 +84,12 @@ LL |           .filter(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:28:21
+   |
+LL |         .filter(|x| to_ref(to_res(*x)).is_ok())
+   |                     ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_filter_map.rs:34:27
@@ -75,6 +116,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:37:41
+   |
+LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+   |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_filter_map.rs:39:30
@@ -117,6 +164,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:45:45
+   |
+LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+   |                                             ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:93:10
@@ -190,5 +243,23 @@ LL |           .filter(|f| f.result_field.is_ok())
 LL | |         .map(|f| f.result_field.to_owned().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
 
-error: aborting due to 27 previous errors
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:146:27
+   |
+LL |       let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+   |  ___________________________^
+LL | |         Enum::A(s) => s,
+LL | |         _ => unreachable!(),
+LL | |     });
+   | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:156:10
+   |
+LL |           .filter(|x| matches!(x, Enum::A(_)))
+   |  __________^
+LL | |         .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+   | |_____________________________________________________________________^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr
index 693a06bb559..4e52b5efacf 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_map.stderr
@@ -4,6 +4,11 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
    |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:9:28
+   |
+LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+   |                            ^^^^^^^^^^
    = note: `-D clippy::manual-find-map` implied by `-D warnings`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
@@ -11,12 +16,24 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:12:29
+   |
+LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+   |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:15:19
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:15:29
+   |
+LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+   |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:18:10
@@ -25,6 +42,12 @@ LL |           .find(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:18:20
+   |
+LL |         .find(|&x| to_ref(to_opt(x)).is_some())
+   |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:21:10
@@ -33,6 +56,12 @@ LL |           .find(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:21:19
+   |
+LL |         .find(|x| to_ref(to_opt(*x)).is_some())
+   |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:25:10
@@ -41,6 +70,12 @@ LL |           .find(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:25:20
+   |
+LL |         .find(|&x| to_ref(to_res(x)).is_ok())
+   |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:28:10
@@ -49,6 +84,12 @@ LL |           .find(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:28:19
+   |
+LL |         .find(|x| to_ref(to_res(*x)).is_ok())
+   |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:34:26
@@ -91,6 +132,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:40:41
+   |
+LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+   |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:42:30
@@ -133,6 +180,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:48:45
+   |
+LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+   |                                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:96:10
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
index 60f59066173..f19149cf9de 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
index afdf1069f5e..8f4e58981ea 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
index c8c1e5da05f..b57b26284ff 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:15:14
+  --> $DIR/match_expr_like_matches_macro.rs:16:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/match_expr_like_matches_macro.rs:21:14
+  --> $DIR/match_expr_like_matches_macro.rs:22:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -23,7 +23,7 @@ LL | |     };
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_expr_like_matches_macro.rs:27:14
+  --> $DIR/match_expr_like_matches_macro.rs:28:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -33,7 +33,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:33:15
+  --> $DIR/match_expr_like_matches_macro.rs:34:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -43,13 +43,13 @@ LL | |     };
    | |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:39:16
+  --> $DIR/match_expr_like_matches_macro.rs:40:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:63:20
+  --> $DIR/match_expr_like_matches_macro.rs:64:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -60,7 +60,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:73:20
+  --> $DIR/match_expr_like_matches_macro.rs:74:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -73,7 +73,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:83:20
+  --> $DIR/match_expr_like_matches_macro.rs:84:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -84,7 +84,7 @@ LL | |         };
    | |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:143:18
+  --> $DIR/match_expr_like_matches_macro.rs:144:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -94,7 +94,7 @@ LL | |         };
    | |_________^ help: try: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:152:18
+  --> $DIR/match_expr_like_matches_macro.rs:153:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:169:21
+  --> $DIR/match_expr_like_matches_macro.rs:170:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -114,7 +114,7 @@ LL | |             };
    | |_____________^ help: try: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:183:20
+  --> $DIR/match_expr_like_matches_macro.rs:184:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -124,7 +124,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:195:20
+  --> $DIR/match_expr_like_matches_macro.rs:196:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -134,7 +134,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:253:14
+  --> $DIR/match_expr_like_matches_macro.rs:254:14
    |
 LL |       let _y = match Some(5) {
    |  ______________^
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs
index 0fab224a29d..03784442e2c 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.rs
+++ b/src/tools/clippy/tests/ui/min_ident_chars.rs
@@ -81,3 +81,7 @@ fn b() {}
 fn wrong_pythagoras(a: f32, b: f32) -> f32 {
     a * a + a * b
 }
+
+mod issue_11163 {
+    struct Array<T, const N: usize>([T; N]);
+}
diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr
index 02a0da86a4b..3f756f5f0e5 100644
--- a/src/tools/clippy/tests/ui/mut_key.stderr
+++ b/src/tools/clippy/tests/ui/mut_key.stderr
@@ -12,14 +12,6 @@ error: mutable key type
 LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
    |                                                                        ^^^^^^^^^^^^
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_key.rs:31:32
-   |
-LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: mutable key type
   --> $DIR/mut_key.rs:32:5
    |
@@ -110,5 +102,13 @@ error: mutable key type
 LL |     let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_key.rs:31:32
+   |
+LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
index 23c812475c2..1fdfbf9227e 100644
--- a/src/tools/clippy/tests/ui/mut_reference.stderr
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -1,17 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:4:33
-   |
-LL | fn takes_a_mutable_reference(a: &mut i32) {}
-   |                                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:11:44
-   |
-LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
-   |                                            ^^^^^^^^ help: consider changing to: `&i32`
-
 error: the function `takes_an_immutable_reference` doesn't need a mutable reference
   --> $DIR/mut_reference.rs:17:34
    |
@@ -32,5 +18,13 @@ error: the method `takes_an_immutable_reference` doesn't need a mutable referenc
 LL |     my_struct.takes_an_immutable_reference(&mut 42);
    |                                            ^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_reference.rs:11:44
+   |
+LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
+   |                                            ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index 5e7280995c6..ae7b018d0e2 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -1,9 +1,10 @@
-#![allow(unused)]
+#![allow(clippy::if_same_then_else, clippy::no_effect)]
+#![feature(lint_reasons)]
 
 use std::ptr::NonNull;
 
-// Should only warn for `s`.
 fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     *x += *b + s.len() as u32;
 }
 
@@ -27,8 +28,8 @@ fn foo5(s: &mut Vec<u32>) {
     foo2(s);
 }
 
-// Should warn.
 fn foo6(s: &mut Vec<u32>) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     non_mut_ref(s);
 }
 
@@ -40,13 +41,13 @@ impl Bar {
     // Should not warn on `&mut self`.
     fn bar(&mut self) {}
 
-    // Should warn about `vec`
     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 
-    // Should warn about `vec` (and not `self`).
     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 }
@@ -91,6 +92,110 @@ impl<T> Mut<T> {
 // Should not warn.
 fn unused(_: &mut u32, _b: &mut u8) {}
 
+// Should not warn.
+async fn f1(x: &mut i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f2(x: &mut i32, y: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f3(x: &mut i32, y: String, z: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f4(x: &mut i32, y: i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f5(x: i32, y: &mut i32) {
+    *y += 1;
+}
+// Should not warn.
+async fn f6(x: i32, y: &mut i32, z: &mut i32) {
+    *y += 1;
+    *z += 1;
+}
+// Should not warn.
+async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) {
+    *x += 1;
+    *z += 1;
+}
+
+async fn a1(x: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a2(x: &mut i32, y: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a3(x: &mut i32, y: String, z: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a4(x: &mut i32, y: i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a5(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a6(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a7(x: i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+
+// Should not warn (passed as closure which takes `&mut`).
+fn passed_as_closure(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_local(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_1(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_2(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_field(s: &mut u32) {}
+
+fn closure_takes_mut(s: fn(&mut u32)) {}
+
+struct A {
+    s: fn(&mut u32),
+}
+
+// Should warn.
+fn used_as_path(s: &mut u32) {}
+
+// Make sure lint attributes work fine
+#[expect(clippy::needless_pass_by_ref_mut)]
+fn lint_attr(s: &mut u32) {}
+
+#[cfg(not(feature = "a"))]
+fn cfg_warn(s: &mut u32) {}
+//~^ ERROR: this argument is a mutable reference, but not used mutably
+//~| NOTE: this is cfg-gated and may require further changes
+
+#[cfg(not(feature = "a"))]
+mod foo {
+    fn cfg_warn(s: &mut u32) {}
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    //~| NOTE: this is cfg-gated and may require further changes
+}
+
 fn main() {
     let mut u = 0;
     let mut v = vec![0];
@@ -102,4 +207,9 @@ fn main() {
     alias_check(&mut v);
     alias_check2(&mut v);
     println!("{u}");
+    closure_takes_mut(passed_as_closure);
+    A { s: passed_as_field };
+    used_as_path;
+    let _: fn(&mut u32) = passed_as_local;
+    let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
 }
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 5e9d80bb6c4..0d426ce32f9 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -24,5 +24,75 @@ error: this argument is a mutable reference, but not used mutably
 LL |     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
    |                               ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
 
-error: aborting due to 4 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:126:16
+   |
+LL | async fn a1(x: &mut i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:130:16
+   |
+LL | async fn a2(x: &mut i32, y: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:134:16
+   |
+LL | async fn a3(x: &mut i32, y: String, z: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:138:16
+   |
+LL | async fn a4(x: &mut i32, y: i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:142:24
+   |
+LL | async fn a5(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:146:24
+   |
+LL | async fn a6(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:150:32
+   |
+LL | async fn a7(x: i32, y: i32, z: &mut i32) {
+   |                                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:24
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:45
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                                             ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:188:16
+   |
+LL | fn cfg_warn(s: &mut u32) {}
+   |                ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:194:20
+   |
+LL |     fn cfg_warn(s: &mut u32) {}
+   |                    ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
new file mode 100644
index 00000000000..d6e47d07b0f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
new file mode 100644
index 00000000000..4fc04d363a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    return Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
new file mode 100644
index 00000000000..e1d91638d2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
@@ -0,0 +1,10 @@
+error: unneeded `return` statement with `?` operator
+  --> $DIR/needless_return_with_question_mark.rs:28:5
+   |
+LL |     return Err(())?;
+   |     ^^^^^^^ help: remove it
+   |
+   = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs
index 65a1b467f81..61dbad939db 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.rs
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs
@@ -9,6 +9,7 @@ use proc_macros::{external, inline_macros};
 fn main() {
     let _ = option_env!("PATH").unwrap();
     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+    let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your environment.
     let _ = inline!(option_env!($"PATH").unwrap());
     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
     let _ = external!(option_env!($"PATH").unwrap());
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
index 7bba62686ee..cfa9dd58a30 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -16,7 +16,15 @@ LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set
    = help: consider using the `env!` macro instead
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:12:21
+  --> $DIR/option_env_unwrap.rs:12:13
+   |
+LL |     let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your env...
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:13:21
    |
 LL |     let _ = inline!(option_env!($"PATH").unwrap());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +33,7 @@ LL |     let _ = inline!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:13:21
+  --> $DIR/option_env_unwrap.rs:14:21
    |
 LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +42,7 @@ LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:14:13
+  --> $DIR/option_env_unwrap.rs:15:13
    |
 LL |     let _ = external!(option_env!($"PATH").unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +51,7 @@ LL |     let _ = external!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:15:13
+  --> $DIR/option_env_unwrap.rs:16:13
    |
 LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,5 +59,5 @@ LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PA
    = help: consider using the `env!` macro instead
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 8e59e4375d2..6fee3cce619 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index e72edf2a8e3..4b3cf948a1b 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index aa2da217400..350f0f07e13 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:12:5
+  --> $DIR/option_if_let_else.rs:13:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:39:13
+  --> $DIR/option_if_let_else.rs:40:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:45:13
+  --> $DIR/option_if_let_else.rs:46:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:54:5
+  --> $DIR/option_if_let_else.rs:55:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:67:13
+  --> $DIR/option_if_let_else.rs:68:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:76:13
+  --> $DIR/option_if_let_else.rs:77:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:109:13
+  --> $DIR/option_if_let_else.rs:110:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,7 +153,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:120:5
+  --> $DIR/option_if_let_else.rs:121:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -172,13 +172,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:143:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:152:13
+  --> $DIR/option_if_let_else.rs:153:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -200,13 +200,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:180:13
+  --> $DIR/option_if_let_else.rs:181:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:184:13
+  --> $DIR/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -226,7 +226,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:223:13
+  --> $DIR/option_if_let_else.rs:224:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -236,7 +236,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:227:13
+  --> $DIR/option_if_let_else.rs:228:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -246,7 +246,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:233:13
+  --> $DIR/option_if_let_else.rs:234:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -256,7 +256,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:237:13
+  --> $DIR/option_if_let_else.rs:238:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -266,13 +266,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:241:13
+  --> $DIR/option_if_let_else.rs:242:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:258:9
+  --> $DIR/option_if_let_else.rs:259:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something(value),
@@ -281,7 +281,7 @@ LL | |         }
    | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:265:9
+  --> $DIR/option_if_let_else.rs:266:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something2(value),
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 6deff0f3240..581f3ad45c7 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -190,7 +190,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn more_to_max_suggestion_highest_lines_1() {
@@ -203,7 +203,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn equal_to_max_suggestion_highest_lines() {
@@ -215,7 +215,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn less_than_max_suggestion_highest_lines() {
@@ -226,7 +226,7 @@ mod issue8239 {
             acc.push_str(&f);
             acc
         })
-        .unwrap_or_default();
+        .unwrap_or(String::new());
     }
 }
 
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_default();
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_default();
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_default();
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_default();
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_default();
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_default();
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_default();
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index b05b33e6ee2..1f3987eb891 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_else(Vec::new);
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_else(Default::default);
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_else(u64::default);
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_else(<FakeDefault as Default>::default);
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_insert_with(String::new);
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_insert_with(String::new);
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_else(String::new);
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 7342b0c2914..519f0916562 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -6,11 +6,13 @@ LL |     with_constructor.unwrap_or(make());
    |
    = note: `-D clippy::or-fun-call` implied by `-D warnings`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:56:14
    |
 LL |     with_new.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+   |
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
 error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:59:21
@@ -30,13 +32,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:68:24
    |
 LL |     with_default_trait.unwrap_or(Default::default());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:71:23
    |
 LL |     with_default_type.unwrap_or(u64::default());
@@ -48,13 +50,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:77:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:80:14
    |
 LL |     with_vec.unwrap_or(vec![]);
@@ -66,31 +68,31 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:86:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:89:23
    |
 LL |     map_vec.entry(42).or_insert(vec![]);
    |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:92:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:95:25
    |
 LL |     btree_vec.entry(42).or_insert(vec![]);
    |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:98:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
@@ -132,30 +134,6 @@ error: use of `unwrap_or` followed by a function call
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:193:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:206:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:218:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:229:10
-   |
-LL |         .unwrap_or(String::new());
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
 error: use of `map_or` followed by a function call
   --> $DIR/or_fun_call.rs:254:25
    |
@@ -168,5 +146,47 @@ error: use of `map_or` followed by a function call
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
-error: aborting due to 28 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:286:18
+   |
+LL |         with_new.unwrap_or_else(Vec::new);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:289:28
+   |
+LL |         with_default_trait.unwrap_or_else(Default::default);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:292:27
+   |
+LL |         with_default_type.unwrap_or_else(u64::default);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:295:22
+   |
+LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:298:23
+   |
+LL |         map.entry(42).or_insert_with(String::new);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:301:25
+   |
+LL |         btree.entry(42).or_insert_with(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:304:25
+   |
+LL |         let _ = stringy.unwrap_or_else(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 13e993d247b..08075c382a2 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -267,3 +267,16 @@ mod issue_9218 {
         todo!()
     }
 }
+
+mod issue_11181 {
+    extern "C" fn allowed(_v: &Vec<u32>) {}
+
+    struct S;
+    impl S {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+
+    trait T {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index c6025ef1f4d..ff2ad8644b4 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::read_zero_byte_vec)]
-#![allow(clippy::unused_io_amount, clippy::needless_pass_by_ref_mut)]
+#![allow(
+    clippy::unused_io_amount,
+    clippy::needless_pass_by_ref_mut,
+    clippy::slow_vector_initialization
+)]
 use std::fs::File;
 use std::io;
 use std::io::prelude::*;
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
index 08ba9753d7c..4c7f605f4c2 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
@@ -1,5 +1,5 @@
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:17:5
+  --> $DIR/read_zero_byte_vec.rs:21:5
    |
 LL |     f.read_exact(&mut data).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();`
@@ -7,55 +7,55 @@ LL |     f.read_exact(&mut data).unwrap();
    = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:21:5
+  --> $DIR/read_zero_byte_vec.rs:25:5
    |
 LL |     f.read_exact(&mut data2)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:25:5
+  --> $DIR/read_zero_byte_vec.rs:29:5
    |
 LL |     f.read_exact(&mut data3)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:29:5
+  --> $DIR/read_zero_byte_vec.rs:33:5
    |
 LL |     let _ = f.read(&mut data4)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:34:9
+  --> $DIR/read_zero_byte_vec.rs:38:9
    |
 LL |         f.read(&mut data5)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:40:9
+  --> $DIR/read_zero_byte_vec.rs:44:9
    |
 LL |         f.read(&mut data6)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:70:5
+  --> $DIR/read_zero_byte_vec.rs:74:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:74:5
+  --> $DIR/read_zero_byte_vec.rs:78:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:80:5
+  --> $DIR/read_zero_byte_vec.rs:84:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:84:5
+  --> $DIR/read_zero_byte_vec.rs:88:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs
new file mode 100644
index 00000000000..656b45787e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::readonly_write_lock)]
+
+use std::sync::RwLock;
+
+fn mutate_i32(x: &mut i32) {
+    *x += 1;
+}
+
+fn accept_i32(_: i32) {}
+
+fn main() {
+    let lock = RwLock::new(42);
+    let lock2 = RwLock::new(1234);
+
+    {
+        let writer = lock.write().unwrap();
+        dbg!(&writer);
+    }
+
+    {
+        let writer = lock.write().unwrap();
+        accept_i32(*writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        mutate_i32(&mut writer);
+        dbg!(&writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        *writer += 1;
+    }
+
+    {
+        let mut writer1 = lock.write().unwrap();
+        let mut writer2 = lock2.write().unwrap();
+        *writer2 += 1;
+        *writer1 = *writer2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.stderr b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
new file mode 100644
index 00000000000..e3d8fce7b2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
@@ -0,0 +1,16 @@
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:16:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+   |
+   = note: `-D clippy::readonly-write-lock` implied by `-D warnings`
+
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:21:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
new file mode 100644
index 00000000000..77ac7666864
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, 1) => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(Some(1)) if true => ..,
+        Some(Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(Some(1)) => ..,
+        Some(Some(2)) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e: Some(A(2)) } => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A("not from an or pattern") => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        Some(0) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
new file mode 100644
index 00000000000..b072e4ea14d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, y) if let 1 = y => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(x) if matches!(x, Some(1) if true) => ..,
+        Some(x) if matches!(x, Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(x) if let Some(1) = x => ..,
+        Some(x) if x == Some(2) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e } if matches!(e, Some(A(2))) => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A(y) if y == "not from an or pattern" => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        x if matches!(x, Some(0)) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr
new file mode 100644
index 00000000000..c2a92071d1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.stderr
@@ -0,0 +1,98 @@
+error: redundant guard
+  --> $DIR/redundant_guards.rs:21:20
+   |
+LL |         C(x, y) if let 1 = y => ..,
+   |                    ^^^^^^^^^
+   |
+   = note: `-D clippy::redundant-guards` implied by `-D warnings`
+help: try
+   |
+LL -         C(x, y) if let 1 = y => ..,
+LL +         C(x, 1) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:27:20
+   |
+LL |         Some(x) if matches!(x, Some(1) if true) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |         Some(Some(1)) if true => ..,
+   |              ~~~~~~~  ~~~~~~~
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:28:20
+   |
+LL |         Some(x) if matches!(x, Some(1)) => {
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if matches!(x, Some(1)) => {
+LL +         Some(Some(1)) => {
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:32:20
+   |
+LL |         Some(x) if let Some(1) = x => ..,
+   |                    ^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if let Some(1) = x => ..,
+LL +         Some(Some(1)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:33:20
+   |
+LL |         Some(x) if x == Some(2) => ..,
+   |                    ^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if x == Some(2) => ..,
+LL +         Some(Some(2)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:56:20
+   |
+LL |         B { e } if matches!(e, Some(A(2))) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         B { e } if matches!(e, Some(A(2))) => ..,
+LL +         B { e: Some(A(2)) } => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:93:20
+   |
+LL |         E::A(y) if y == "not from an or pattern" => {},
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         E::A(y) if y == "not from an or pattern" => {},
+LL +         E::A("not from an or pattern") => {},
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:100:14
+   |
+LL |         x if matches!(x, Some(0)) => ..,
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         x if matches!(x, Some(0)) => ..,
+LL +         Some(0) => ..,
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
new file mode 100644
index 00000000000..e74c78a50b6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -0,0 +1,111 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
+#![warn(clippy::redundant_locals)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+fn main() {}
+
+fn immutable() {
+    let x = 1;
+    let x = x;
+}
+
+fn mutable() {
+    let mut x = 1;
+    let mut x = x;
+}
+
+fn upgraded_mutability() {
+    let x = 1;
+    let mut x = x;
+}
+
+fn downgraded_mutability() {
+    let mut x = 1;
+    let x = x;
+}
+
+fn coercion(par: &mut i32) {
+    let par: &i32 = par;
+
+    let x: &mut i32 = &mut 1;
+    let x: &i32 = x;
+}
+
+fn parameter(x: i32) {
+    let x = x;
+}
+
+fn many() {
+    let x = 1;
+    let x = x;
+    let x = x;
+    let x = x;
+    let x = x;
+}
+
+fn interleaved() {
+    let a = 1;
+    let b = 2;
+    let a = a;
+    let b = b;
+}
+
+fn block() {
+    {
+        let x = 1;
+        let x = x;
+    }
+}
+
+fn closure() {
+    || {
+        let x = 1;
+        let x = x;
+    };
+    |x: i32| {
+        let x = x;
+    };
+}
+
+fn consequential_drop_order() {
+    use std::sync::Mutex;
+
+    let mutex = Mutex::new(1);
+    let guard = mutex.lock().unwrap();
+
+    {
+        let guard = guard;
+    }
+}
+
+fn inconsequential_drop_order() {
+    let x = 1;
+
+    {
+        let x = x;
+    }
+}
+
+fn macros() {
+    macro_rules! rebind {
+        ($x:ident) => {
+            let $x = 1;
+            let $x = $x;
+        };
+    }
+
+    rebind!(x);
+
+    external! {
+        let x = 1;
+        let x = x;
+    }
+    with_span! {
+        span
+        let x = 1;
+        let x = x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
new file mode 100644
index 00000000000..df07dd2f453
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -0,0 +1,136 @@
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:11:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+   = note: `-D clippy::redundant-locals` implied by `-D warnings`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:16:9
+   |
+LL |     let mut x = 1;
+   |         ^^^^^
+LL |     let mut x = x;
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:37:14
+   |
+LL | fn parameter(x: i32) {
+   |              ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:42:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:43:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:44:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:45:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:50:9
+   |
+LL |     let a = 1;
+   |         ^
+LL |     let b = 2;
+LL |     let a = a;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `a`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:51:9
+   |
+LL |     let b = 2;
+   |         ^
+LL |     let a = a;
+LL |     let b = b;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `b`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:58:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:65:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:68:6
+   |
+LL |     |x: i32| {
+   |      ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:85:9
+   |
+LL |     let x = 1;
+   |         ^
+...
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index a63ba5809e4..d9fcd98c56e 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -10,6 +10,20 @@
     clippy::equatable_if_let,
     clippy::if_same_then_else
 )]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+    maybe_some.is_none() && (!boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+    let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses
+    let _ = match maybe_some { // can't use `matches!` here
+                               // because `expr` metavars in macros don't allow let exprs
+        None if let Some(x) = Some(0) && x > 5 => true,
+        _ => false
+    };
+}
 
 fn main() {
     if None::<()>.is_none() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 631f9091672..cbd9494f15a 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -10,6 +10,20 @@
     clippy::equatable_if_let,
     clippy::if_same_then_else
 )]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+    matches!(maybe_some, None if !boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+    let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+    let _ = match maybe_some { // can't use `matches!` here
+                               // because `expr` metavars in macros don't allow let exprs
+        None if let Some(x) = Some(0) && x > 5 => true,
+        _ => false
+    };
+}
 
 fn main() {
     if let None = None::<()> {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 097ca827a42..b0e43924dbc 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -1,49 +1,61 @@
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:15:12
+  --> $DIR/redundant_pattern_matching_option.rs:16:5
    |
-LL |     if let None = None::<()> {}
-   |     -------^^^^------------- help: try: `if None::<()>.is_none()`
+LL |     matches!(maybe_some, None if !boolean)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)`
    |
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:20:13
+   |
+LL |     let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:29:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^------------- help: try: `if None::<()>.is_none()`
+
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:17:12
+  --> $DIR/redundant_pattern_matching_option.rs:31:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:19:12
+  --> $DIR/redundant_pattern_matching_option.rs:33:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:25:15
+  --> $DIR/redundant_pattern_matching_option.rs:39:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:27:15
+  --> $DIR/redundant_pattern_matching_option.rs:41:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:29:15
+  --> $DIR/redundant_pattern_matching_option.rs:43:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:32:15
+  --> $DIR/redundant_pattern_matching_option.rs:46:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:40:5
+  --> $DIR/redundant_pattern_matching_option.rs:54:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -52,7 +64,7 @@ LL | |     };
    | |_____^ help: try: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:45:5
+  --> $DIR/redundant_pattern_matching_option.rs:59:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -61,7 +73,7 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:50:13
+  --> $DIR/redundant_pattern_matching_option.rs:64:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -71,55 +83,55 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:56:20
+  --> $DIR/redundant_pattern_matching_option.rs:70:20
    |
 LL |     let _ = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:62:20
+  --> $DIR/redundant_pattern_matching_option.rs:76:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:64:19
+  --> $DIR/redundant_pattern_matching_option.rs:78:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:70:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let Some(..) = gen_opt() {}
    |     -------^^^^^^^^------------ help: try: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:85:12
+  --> $DIR/redundant_pattern_matching_option.rs:99:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:87:12
+  --> $DIR/redundant_pattern_matching_option.rs:101:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:89:15
+  --> $DIR/redundant_pattern_matching_option.rs:103:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:91:15
+  --> $DIR/redundant_pattern_matching_option.rs:105:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:93:5
+  --> $DIR/redundant_pattern_matching_option.rs:107:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -128,7 +140,7 @@ LL | |     };
    | |_____^ help: try: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:98:5
+  --> $DIR/redundant_pattern_matching_option.rs:112:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -137,19 +149,19 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:106:12
+  --> $DIR/redundant_pattern_matching_option.rs:120:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:107:12
+  --> $DIR/redundant_pattern_matching_option.rs:121:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:113:5
+  --> $DIR/redundant_pattern_matching_option.rs:127:5
    |
 LL | /     match x {
 LL | |         Some(_) => true,
@@ -158,7 +170,7 @@ LL | |     };
    | |_____^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:118:5
+  --> $DIR/redundant_pattern_matching_option.rs:132:5
    |
 LL | /     match x {
 LL | |         None => true,
@@ -167,7 +179,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:123:5
+  --> $DIR/redundant_pattern_matching_option.rs:137:5
    |
 LL | /     match x {
 LL | |         Some(_) => false,
@@ -176,7 +188,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:128:5
+  --> $DIR/redundant_pattern_matching_option.rs:142:5
    |
 LL | /     match x {
 LL | |         None => false,
@@ -185,16 +197,16 @@ LL | |     };
    | |_____^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:143:13
+  --> $DIR/redundant_pattern_matching_option.rs:157:13
    |
 LL |     let _ = matches!(x, Some(_));
    |             ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:145:13
+  --> $DIR/redundant_pattern_matching_option.rs:159:13
    |
 LL |     let _ = matches!(x, None);
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
 
-error: aborting due to 28 previous errors
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 03d9ea41a0b..8ec19b120d1 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_add_str)]
 #![warn(clippy::module_name_repetitions)]
 #![warn(clippy::recursive_format_impl)]
+#![warn(clippy::unwrap_or_default)]
 #![warn(clippy::invisible_characters)]
 #![warn(invalid_reference_casting)]
 #![warn(suspicious_double_ref_op)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index c028fcb5a37..51a5976eb61 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_push_str)]
 #![warn(clippy::stutter)]
 #![warn(clippy::to_string_in_display)]
+#![warn(clippy::unwrap_or_else_default)]
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::cast_ref_to_mut)]
 #![warn(clippy::clone_double_ref)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 4d8a7fd70f4..e420ea1d2ad 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,316 +7,322 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+  --> $DIR/rename.rs:82:9
+   |
+LL | #![warn(clippy::unwrap_or_else_default)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:92:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> $DIR/rename.rs:91:9
+  --> $DIR/rename.rs:93:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> $DIR/rename.rs:92:9
+  --> $DIR/rename.rs:94:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks`
-  --> $DIR/rename.rs:93:9
+  --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:94:9
+  --> $DIR/rename.rs:96:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:95:9
+  --> $DIR/rename.rs:97:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:96:9
+  --> $DIR/rename.rs:98:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> $DIR/rename.rs:97:9
+  --> $DIR/rename.rs:99:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:98:9
+  --> $DIR/rename.rs:100:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:99:9
+  --> $DIR/rename.rs:101:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:100:9
+  --> $DIR/rename.rs:102:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:101:9
+  --> $DIR/rename.rs:103:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:102:9
+  --> $DIR/rename.rs:104:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> $DIR/rename.rs:103:9
+  --> $DIR/rename.rs:105:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:104:9
+  --> $DIR/rename.rs:106:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:105:9
+  --> $DIR/rename.rs:107:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 53 previous errors
+error: aborting due to 54 previous errors
 
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
index 119ff25918a..6850eeb7a4c 100644
--- a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
@@ -15,5 +15,5 @@ fn main() {
     // A non-Some `f` closure where the argument is not used as the
     // return should not emit the lint
     let opt: Result<u32, &str> = Ok(1);
-    opt.map_or(None, |_x| Some(1));
+    _ = opt.map_or(None, |_x| Some(1));
 }
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
index eeeef830af0..8e151814407 100644
--- a/src/tools/clippy/tests/ui/result_map_or_into_option.rs
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
@@ -15,5 +15,5 @@ fn main() {
     // A non-Some `f` closure where the argument is not used as the
     // return should not emit the lint
     let opt: Result<u32, &str> = Ok(1);
-    opt.map_or(None, |_x| Some(1));
+    _ = opt.map_or(None, |_x| Some(1));
 }
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
new file mode 100644
index 00000000000..653f4533b33
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
@@ -0,0 +1,123 @@
+//@run-rustfix
+#![warn(clippy::semicolon_if_nothing_returned)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
+
+fn get_unit() {}
+
+// the functions below trigger the lint
+fn main() {
+    println!("Hello");
+}
+
+fn hello() {
+    get_unit();
+}
+
+fn basic101(x: i32) {
+    let y: i32;
+    y = x + 1;
+}
+
+#[rustfmt::skip]
+fn closure_error() {
+    let _d = || {
+        hello();
+    };
+}
+
+#[rustfmt::skip]
+fn unsafe_checks_error() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe {
+        ptr::drop_in_place(s.as_mut_ptr());
+    };
+}
+
+// this is fine
+fn print_sum(a: i32, b: i32) {
+    println!("{}", a + b);
+    assert_eq!(true, false);
+}
+
+fn foo(x: i32) {
+    let y: i32;
+    if x < 1 {
+        y = 4;
+    } else {
+        y = 5;
+    }
+}
+
+fn bar(x: i32) {
+    let y: i32;
+    match x {
+        1 => y = 4,
+        _ => y = 32,
+    }
+}
+
+fn foobar(x: i32) {
+    let y: i32;
+    'label: {
+        y = x + 1;
+    }
+}
+
+fn loop_test(x: i32) {
+    let y: i32;
+    for &ext in &["stdout", "stderr", "fixed"] {
+        println!("{}", ext);
+    }
+}
+
+fn closure() {
+    let _d = || hello();
+}
+
+#[rustfmt::skip]
+fn closure_block() {
+    let _d = || { hello() };
+}
+
+unsafe fn some_unsafe_op() {}
+unsafe fn some_other_unsafe_fn() {}
+
+fn do_something() {
+    unsafe { some_unsafe_op() };
+
+    unsafe { some_other_unsafe_fn() };
+}
+
+fn unsafe_checks() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
+}
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+    macro_rules! repro {
+        () => {
+            while false {
+            }
+        };
+    }
+    repro!();
+}
+
+fn function_returning_option() -> Option<i32> {
+    Some(1)
+}
+
+// No warning
+fn let_else_stmts() {
+    let Some(x) = function_returning_option() else {
+        return;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
index 8e7f1d862cf..9db038219b4 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
@@ -1,5 +1,6 @@
+//@run-rustfix
 #![warn(clippy::semicolon_if_nothing_returned)]
-#![allow(clippy::redundant_closure, clippy::uninlined_format_args)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
 
 fn get_unit() {}
 
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
index 8d9a67585cf..78813e7cc1c 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
@@ -1,5 +1,5 @@
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:8:5
+  --> $DIR/semicolon_if_nothing_returned.rs:9:5
    |
 LL |     println!("Hello")
    |     ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
@@ -7,25 +7,25 @@ LL |     println!("Hello")
    = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:12:5
+  --> $DIR/semicolon_if_nothing_returned.rs:13:5
    |
 LL |     get_unit()
    |     ^^^^^^^^^^ help: add a `;` here: `get_unit();`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:17:5
+  --> $DIR/semicolon_if_nothing_returned.rs:18:5
    |
 LL |     y = x + 1
    |     ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:23:9
+  --> $DIR/semicolon_if_nothing_returned.rs:24:9
    |
 LL |         hello()
    |         ^^^^^^^ help: add a `;` here: `hello();`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:34:9
+  --> $DIR/semicolon_if_nothing_returned.rs:35:9
    |
 LL |         ptr::drop_in_place(s.as_mut_ptr())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 9be8c5e59d0..1b40a43d019 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -1,7 +1,12 @@
 //@aux-build:proc_macro_derive.rs:proc-macro
 
 #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
-#![allow(clippy::let_unit_value, clippy::needless_if)]
+#![allow(
+    clippy::let_unit_value,
+    clippy::needless_if,
+    clippy::redundant_guards,
+    clippy::redundant_locals
+)]
 
 extern crate proc_macro_derive;
 
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 8321f6df224..88b02f53be1 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:18:9
+  --> $DIR/shadow.rs:23:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:20:13
+  --> $DIR/shadow.rs:25:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:25:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:33:9
+  --> $DIR/shadow.rs:38:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:35:9
+  --> $DIR/shadow.rs:40:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:34:9
+  --> $DIR/shadow.rs:39:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:50:9
+  --> $DIR/shadow.rs:55:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:49:9
+  --> $DIR/shadow.rs:54:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:13
+  --> $DIR/shadow.rs:60:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:54:10
+  --> $DIR/shadow.rs:59:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:61:17
+  --> $DIR/shadow.rs:66:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:65:17
+  --> $DIR/shadow.rs:70:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:66:20
+  --> $DIR/shadow.rs:71:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:68:13
+  --> $DIR/shadow.rs:73:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:71:17
+  --> $DIR/shadow.rs:76:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:70:9
+  --> $DIR/shadow.rs:75:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:107:9
+  --> $DIR/shadow.rs:112:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:106:28
+  --> $DIR/shadow.rs:111:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:113:21
+  --> $DIR/shadow.rs:118:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:112:13
+  --> $DIR/shadow.rs:117:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
index 2ae9fa34d14..a3bb05bf176 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
@@ -39,15 +39,6 @@ LL | |     }
    |
    = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/method_list_2.rs:38:31
-   |
-LL |     pub fn hash(&self, state: &mut T) {
-   |                               ^^^^^^ help: consider changing to: `&T`
-   |
-   = warning: changing this function will impact semver compatibility
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: method `index` can be confused for the standard trait method `std::ops::Index::index`
   --> $DIR/method_list_2.rs:42:5
    |
@@ -158,5 +149,14 @@ LL | |     }
    |
    = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/method_list_2.rs:38:31
+   |
+LL |     pub fn hash(&self, state: &mut T) {
+   |                               ^^^^^^ help: consider changing to: `&T`
+   |
+   = warning: changing this function will impact semver compatibility
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
index eb8524167c4..8065e9e5fbc 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
@@ -51,6 +51,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
index f7fa65ea922..1620b76843a 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
@@ -50,6 +50,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
index ca4fede17c9..b5cad88ad3f 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -23,7 +23,7 @@ LL +     drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:79:13
+  --> $DIR/significant_drop_tightening.rs:106:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -43,7 +43,7 @@ LL +         drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:100:13
+  --> $DIR/significant_drop_tightening.rs:127:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -67,7 +67,7 @@ LL +
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:106:17
+  --> $DIR/significant_drop_tightening.rs:133:17
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(vec![1i32]);
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index e7b1fd6a85f..163ba94aff8 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index 1515a7053e5..0dcdb125ffd 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 76f7e789589..d3536159949 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:14:5
+  --> $DIR/single_match.rs:15:5
    |
 LL | /     match x {
 LL | |         Some(y) => {
@@ -18,7 +18,7 @@ LL ~     };
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:22:5
+  --> $DIR/single_match.rs:23:5
    |
 LL | /     match x {
 LL | |         // Note the missing block braces.
@@ -30,7 +30,7 @@ LL | |     }
    | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:31:5
+  --> $DIR/single_match.rs:32:5
    |
 LL | /     match z {
 LL | |         (2..=3, 7..=9) => dummy(),
@@ -39,7 +39,7 @@ LL | |     };
    | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:60:5
+  --> $DIR/single_match.rs:61:5
    |
 LL | /     match x {
 LL | |         Some(y) => dummy(),
@@ -48,7 +48,7 @@ LL | |     };
    | |_____^ help: try: `if let Some(y) = x { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:65:5
+  --> $DIR/single_match.rs:66:5
    |
 LL | /     match y {
 LL | |         Ok(y) => dummy(),
@@ -57,7 +57,7 @@ LL | |     };
    | |_____^ help: try: `if let Ok(y) = y { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:72:5
+  --> $DIR/single_match.rs:73:5
    |
 LL | /     match c {
 LL | |         Cow::Borrowed(..) => dummy(),
@@ -66,7 +66,7 @@ LL | |     };
    | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:93:5
+  --> $DIR/single_match.rs:94:5
    |
 LL | /     match x {
 LL | |         "test" => println!(),
@@ -75,7 +75,7 @@ LL | |     }
    | |_____^ help: try: `if x == "test" { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:106:5
+  --> $DIR/single_match.rs:107:5
    |
 LL | /     match x {
 LL | |         Foo::A => println!(),
@@ -84,7 +84,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:112:5
+  --> $DIR/single_match.rs:113:5
    |
 LL | /     match x {
 LL | |         FOO_C => println!(),
@@ -93,7 +93,7 @@ LL | |     }
    | |_____^ help: try: `if x == FOO_C { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:117:5
+  --> $DIR/single_match.rs:118:5
    |
 LL | /     match &&x {
 LL | |         Foo::A => println!(),
@@ -102,7 +102,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:123:5
+  --> $DIR/single_match.rs:124:5
    |
 LL | /     match &x {
 LL | |         Foo::A => println!(),
@@ -111,7 +111,7 @@ LL | |     }
    | |_____^ help: try: `if x == &Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:140:5
+  --> $DIR/single_match.rs:141:5
    |
 LL | /     match x {
 LL | |         Bar::A => println!(),
@@ -120,7 +120,7 @@ LL | |     }
    | |_____^ help: try: `if let Bar::A = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:148:5
+  --> $DIR/single_match.rs:149:5
    |
 LL | /     match x {
 LL | |         None => println!(),
@@ -129,7 +129,7 @@ LL | |     };
    | |_____^ help: try: `if let None = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:170:5
+  --> $DIR/single_match.rs:171:5
    |
 LL | /     match x {
 LL | |         (Some(_), _) => {},
@@ -138,7 +138,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(_), _) = x {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:176:5
+  --> $DIR/single_match.rs:177:5
    |
 LL | /     match x {
 LL | |         (Some(E::V), _) => todo!(),
@@ -147,7 +147,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:182:5
+  --> $DIR/single_match.rs:183:5
    |
 LL | /     match (Some(42), Some(E::V), Some(42)) {
 LL | |         (.., Some(E::V), _) => {},
@@ -156,7 +156,7 @@ LL | |     }
    | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:254:5
+  --> $DIR/single_match.rs:255:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -176,7 +176,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:262:5
+  --> $DIR/single_match.rs:263:5
    |
 LL | /     match bar {
 LL | |         #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index 16be9f6d203..cfb856861b8 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -4,6 +4,7 @@ fn main() {
     resize_vector();
     extend_vector();
     mixed_extend_resize_vector();
+    from_empty_vec();
 }
 
 fn extend_vector() {
@@ -59,6 +60,21 @@ fn resize_vector() {
     vec1.resize(10, 0);
 }
 
+fn from_empty_vec() {
+    // Resize with constant expression
+    let len = 300;
+    let mut vec1 = Vec::new();
+    vec1.resize(len, 0);
+
+    // Resize with len expression
+    let mut vec3 = Vec::new();
+    vec3.resize(len - 10, 0);
+
+    // Reinitialization should be warned
+    vec1 = Vec::new();
+    vec1.resize(10, 0);
+}
+
 fn do_stuff(vec: &mut [u8]) {}
 
 fn extend_vector_with_manipulations_between() {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index 22376680a8e..532ce4ac191 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -1,84 +1,108 @@
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:13:5
+  --> $DIR/slow_vector_initialization.rs:14:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.extend(repeat(0).take(len));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:17:5
+  --> $DIR/slow_vector_initialization.rs:18:5
    |
 LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec2.extend(repeat(0).take(len - 10));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:24:5
+  --> $DIR/slow_vector_initialization.rs:25:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.extend(repeat(0).take(vec4.capacity()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:34:5
+  --> $DIR/slow_vector_initialization.rs:35:5
    |
 LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     resized_vec.resize(30, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:37:5
+  --> $DIR/slow_vector_initialization.rs:38:5
    |
 LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     extend_vec.extend(repeat(0).take(30));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:44:5
+  --> $DIR/slow_vector_initialization.rs:45:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.resize(len, 0);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:52:5
+  --> $DIR/slow_vector_initialization.rs:53:5
    |
 LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec3.resize(len - 10, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:55:5
+  --> $DIR/slow_vector_initialization.rs:56:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.resize(vec4.capacity(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:59:5
+  --> $DIR/slow_vector_initialization.rs:60:5
    |
 LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replace allocation with: `vec![0; 10]`
+   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:67:5
+   |
+LL |     let mut vec1 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len]`
+LL |     vec1.resize(len, 0);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:71:5
+   |
+LL |     let mut vec3 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
+LL |     vec3.resize(len - 10, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:75:5
+   |
+LL |     vec1 = Vec::new();
+   |            ---------- help: consider replacing this with: `vec![0; 10]`
 LL |     vec1.resize(10, 0);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: this argument is a mutable reference, but not used mutably
-  --> $DIR/slow_vector_initialization.rs:62:18
+  --> $DIR/slow_vector_initialization.rs:78:18
    |
 LL | fn do_stuff(vec: &mut [u8]) {}
    |                  ^^^^^^^^^ help: consider changing to: `&[u8]`
    |
    = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.fixed b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
new file mode 100644
index 00000000000..d7ab9c3397a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+    fn chars(&self) -> impl Iterator<Item = char> {
+        "c".chars()
+    }
+}
+
+fn main() {
+    let c = 'c';
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    #[rustfmt::skip]
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    // Do not lint
+    NotStringLit.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        let c = 'c';
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        1;
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+    matches!(
+        c,
+        '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+    );
+    external! {
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+    with_span! {
+        span
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.rs b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
new file mode 100644
index 00000000000..9408d7bb239
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+    fn chars(&self) -> impl Iterator<Item = char> {
+        "c".chars()
+    }
+}
+
+fn main() {
+    let c = 'c';
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+    r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+    #[rustfmt::skip]
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+    // Do not lint
+    NotStringLit.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        let c = 'c';
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        1;
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+    matches!(
+        c,
+        '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+    );
+    external! {
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+    with_span! {
+        span
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
new file mode 100644
index 00000000000..ff951b73ded
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
@@ -0,0 +1,58 @@
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:19:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::string-lit-chars-any` implied by `-D warnings`
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:20:5
+   |
+LL |     r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:21:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:22:5
+   |
+LL |     r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:24:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 22f904e3fd9..7b74a83b6df 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index ada64f89e6d..93855cd7b5c 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index a3b9c2b744c..1097b29bba0 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:28:5
+  --> $DIR/swap.rs:29:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:40:5
+  --> $DIR/swap.rs:41:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:49:5
+  --> $DIR/swap.rs:50:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:68:5
+  --> $DIR/swap.rs:69:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:79:5
+  --> $DIR/swap.rs:80:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:87:5
+  --> $DIR/swap.rs:88:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:95:5
+  --> $DIR/swap.rs:96:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:124:5
+  --> $DIR/swap.rs:125:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:138:7
+  --> $DIR/swap.rs:139:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:147:7
+  --> $DIR/swap.rs:148:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -90,7 +90,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `b` and `a` manually
-  --> $DIR/swap.rs:173:5
+  --> $DIR/swap.rs:174:5
    |
 LL | /     let t = b;
 LL | |     b = a;
@@ -100,7 +100,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:135:5
+  --> $DIR/swap.rs:136:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -110,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:144:5
+  --> $DIR/swap.rs:145:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -119,7 +119,7 @@ LL | |     a = c.0;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:151:5
+  --> $DIR/swap.rs:152:5
    |
 LL | /     let a = b;
 LL | |     let b = a;
@@ -128,7 +128,7 @@ LL | |     let b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `d` and `c`
-  --> $DIR/swap.rs:156:5
+  --> $DIR/swap.rs:157:5
    |
 LL | /     d = c;
 LL | |     c = d;
@@ -137,7 +137,7 @@ LL | |     c = d;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:160:5
+  --> $DIR/swap.rs:161:5
    |
 LL | /     let a = b;
 LL | |     b = a;
@@ -146,7 +146,7 @@ LL | |     b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:208:5
+  --> $DIR/swap.rs:209:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index 1816740870a..930489fab76 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 0e47c4d023e..f5baf3d8f74 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr
index 79f7b70224a..9968b383ebb 100644
--- a/src/tools/clippy/tests/ui/try_err.stderr
+++ b/src/tools/clippy/tests/ui/try_err.stderr
@@ -1,5 +1,5 @@
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:19:9
+  --> $DIR/try_err.rs:23:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err)`
@@ -11,25 +11,25 @@ LL | #![deny(clippy::try_err)]
    |         ^^^^^^^^^^^^^^^
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:29:9
+  --> $DIR/try_err.rs:33:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:49:17
+  --> $DIR/try_err.rs:53:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err)`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:68:17
+  --> $DIR/try_err.rs:72:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:88:23
+  --> $DIR/try_err.rs:92:23
    |
 LL |             Err(_) => Err(1)?,
    |                       ^^^^^^^ help: try: `return Err(1)`
@@ -37,7 +37,7 @@ LL |             Err(_) => Err(1)?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:95:23
+  --> $DIR/try_err.rs:99:23
    |
 LL |             Err(_) => Err(inline!(1))?,
    |                       ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))`
@@ -45,31 +45,31 @@ LL |             Err(_) => Err(inline!(1))?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:122:9
+  --> $DIR/try_err.rs:126:9
    |
 LL |         Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:129:9
+  --> $DIR/try_err.rs:133:9
    |
 LL |         Err(io::ErrorKind::WriteZero)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:131:9
+  --> $DIR/try_err.rs:135:9
    |
 LL |         Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:139:9
+  --> $DIR/try_err.rs:143:9
    |
 LL |         Err(io::ErrorKind::NotFound)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:148:16
+  --> $DIR/try_err.rs:152:16
    |
 LL |         return Err(42)?;
    |                ^^^^^^^^ help: try: `Err(42)`
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.rs b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
index f96a7c97f1a..569415acbce 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.rs
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
@@ -52,6 +52,36 @@ fn main() {
         let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();
         let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect();
     }
+    // FP #11082; needs discussion
+    let (a, b) = (1.0f64, 2.0f64);
+    let _: &[f64] = &[a, b];
+    // FP #11085; impossible to fix
+    let [src, dest]: [_; 2] = [1, 2];
+    (src, dest);
+    // FP #11100
+    fn issue_11100_array_to_tuple(this: [&mut i32; 2]) -> (&i32, &mut i32) {
+        let [input, output] = this;
+        (input, output)
+    }
+
+    fn issue_11100_tuple_to_array<'a>(this: (&'a mut i32, &'a mut i32)) -> [&'a i32; 2] {
+        let (input, output) = this;
+        [input, output]
+    }
+    // FP #11124
+    // tuple=>array
+    let (a, b) = (1, 2);
+    [a, b];
+    let x = a;
+    // array=>tuple
+    let [a, b] = [1, 2];
+    (a, b);
+    let x = a;
+    // FP #11144
+    let (a, (b, c)) = (1, (2, 3));
+    [a, c];
+    let [[a, b], [c, d]] = [[1, 2], [3, 4]];
+    (a, c);
 }
 
 #[clippy::msrv = "1.70.0"]
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
index be653e8efb7..50bdcf29d1f 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
@@ -15,14 +15,6 @@ LL |     let x = [x.0, x.1];
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
-error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:13:13
-   |
-LL |     let x = (x[0], x[1]);
-   |             ^^^^^^^^^^^^
-   |
-   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
 error: it looks like you're trying to convert a tuple to an array
   --> $DIR/tuple_array_conversions.rs:16:53
    |
@@ -55,8 +47,24 @@ LL |     t1.iter().for_each(|&(a, b)| _ = [a, b]);
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
+error: it looks like you're trying to convert a tuple to an array
+  --> $DIR/tuple_array_conversions.rs:57:22
+   |
+LL |     let _: &[f64] = &[a, b];
+   |                      ^^^^^^
+   |
+   = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
+
 error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:69:13
+  --> $DIR/tuple_array_conversions.rs:60:5
+   |
+LL |     (src, dest);
+   |     ^^^^^^^^^^^
+   |
+   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
+
+error: it looks like you're trying to convert an array to a tuple
+  --> $DIR/tuple_array_conversions.rs:99:13
    |
 LL |     let x = (x[0], x[1]);
    |             ^^^^^^^^^^^^
@@ -64,20 +72,12 @@ LL |     let x = (x[0], x[1]);
    = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
 
 error: it looks like you're trying to convert a tuple to an array
-  --> $DIR/tuple_array_conversions.rs:70:13
+  --> $DIR/tuple_array_conversions.rs:100:13
    |
 LL |     let x = [x.0, x.1];
    |             ^^^^^^^^^^
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
-error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:72:13
-   |
-LL |     let x = (x[0], x[1]);
-   |             ^^^^^^^^^^^^
-   |
-   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
 error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index 8efd44baf59..2bf02f13414 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa();
+    let x = aaa();
+    aaa();
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index c7723ef51f9..25b6b0f9b07 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa() as u32;
+    let x = aaa();
+    aaa() as u32;
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index f0443556fb4..19411a01b67 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -7,226 +7,238 @@ LL |     ptr as *const T
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:44:5
+  --> $DIR/unnecessary_cast.rs:54:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:45:5
+  --> $DIR/unnecessary_cast.rs:55:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/unnecessary_cast.rs:46:5
+  --> $DIR/unnecessary_cast.rs:56:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:49:5
+  --> $DIR/unnecessary_cast.rs:59:5
    |
 LL |     -1_i32 as i32;
    |     ^^^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:50:5
+  --> $DIR/unnecessary_cast.rs:60:5
    |
 LL |     - 1_i32 as i32;
    |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:51:5
+  --> $DIR/unnecessary_cast.rs:61:5
    |
 LL |     -1f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `-1_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:52:5
+  --> $DIR/unnecessary_cast.rs:62:5
    |
 LL |     1_i32 as i32;
    |     ^^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:53:5
+  --> $DIR/unnecessary_cast.rs:63:5
    |
 LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:55:22
+  --> $DIR/unnecessary_cast.rs:65:22
    |
 LL |     let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:57:5
+  --> $DIR/unnecessary_cast.rs:67:5
    |
 LL |     [1u8, 2].as_ptr() as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`)
-  --> $DIR/unnecessary_cast.rs:59:5
+  --> $DIR/unnecessary_cast.rs:69:5
    |
 LL |     [1u8, 2].as_mut_ptr() as *mut u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:70:5
+  --> $DIR/unnecessary_cast.rs:80:5
    |
 LL |     owo::<u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:71:5
+  --> $DIR/unnecessary_cast.rs:81:5
    |
 LL |     uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:73:5
+  --> $DIR/unnecessary_cast.rs:83:5
    |
 LL |     uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
 
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:118:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:120:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:139:9
+  --> $DIR/unnecessary_cast.rs:156:9
    |
 LL |         100 as f32;
    |         ^^^^^^^^^^ help: try: `100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:140:9
+  --> $DIR/unnecessary_cast.rs:157:9
    |
 LL |         100 as f64;
    |         ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:141:9
+  --> $DIR/unnecessary_cast.rs:158:9
    |
 LL |         100_i32 as f64;
    |         ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:142:17
+  --> $DIR/unnecessary_cast.rs:159:17
    |
 LL |         let _ = -100 as f32;
    |                 ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:143:17
+  --> $DIR/unnecessary_cast.rs:160:17
    |
 LL |         let _ = -100 as f64;
    |                 ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:144:17
+  --> $DIR/unnecessary_cast.rs:161:17
    |
 LL |         let _ = -100_i32 as f64;
    |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:145:9
+  --> $DIR/unnecessary_cast.rs:162:9
    |
 LL |         100. as f32;
    |         ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:146:9
+  --> $DIR/unnecessary_cast.rs:163:9
    |
 LL |         100. as f64;
    |         ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:158:9
+  --> $DIR/unnecessary_cast.rs:175:9
    |
 LL |         1 as u32;
    |         ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:159:9
+  --> $DIR/unnecessary_cast.rs:176:9
    |
 LL |         0x10 as i32;
    |         ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast.rs:160:9
+  --> $DIR/unnecessary_cast.rs:177:9
    |
 LL |         0b10 as usize;
    |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast.rs:161:9
+  --> $DIR/unnecessary_cast.rs:178:9
    |
 LL |         0o73 as u16;
    |         ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:162:9
+  --> $DIR/unnecessary_cast.rs:179:9
    |
 LL |         1_000_000_000 as u32;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:164:9
+  --> $DIR/unnecessary_cast.rs:181:9
    |
 LL |         1.0 as f64;
    |         ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:165:9
+  --> $DIR/unnecessary_cast.rs:182:9
    |
 LL |         0.5 as f32;
    |         ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:169:17
+  --> $DIR/unnecessary_cast.rs:186:17
    |
 LL |         let _ = -1 as i32;
    |                 ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:170:17
+  --> $DIR/unnecessary_cast.rs:187:17
    |
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
 error: casting to the same type is unnecessary (`i32` -> `i32`)
-  --> $DIR/unnecessary_cast.rs:176:18
+  --> $DIR/unnecessary_cast.rs:193:18
    |
 LL |         let _ = &(x as i32);
    |                  ^^^^^^^^^^ help: try: `{ x }`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:182:22
+  --> $DIR/unnecessary_cast.rs:199:22
    |
 LL |         let _: i32 = -(1) as i32;
    |                      ^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:184:22
+  --> $DIR/unnecessary_cast.rs:201:22
    |
 LL |         let _: i64 = -(1) as i64;
    |                      ^^^^^^^^^^^ help: try: `-1_i64`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:191:22
+  --> $DIR/unnecessary_cast.rs:208:22
    |
 LL |         let _: f64 = (-8.0 as f64).exp();
    |                      ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:193:23
+  --> $DIR/unnecessary_cast.rs:210:23
    |
 LL |         let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
    |                       ^^^^^^^^^^^^ help: try: `8.0_f64`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> $DIR/unnecessary_cast.rs:201:20
+  --> $DIR/unnecessary_cast.rs:218:20
    |
 LL |         let _num = foo() as f32;
    |                    ^^^^^^^^^^^^ help: try: `foo()`
 
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
index 8e01c2674f1..3c8c6ec94c1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
@@ -148,3 +148,9 @@ mod comment_1052978898 {
         })
     }
 }
+
+fn issue11260() {
+    // #11260 is about unnecessary_find_map, but the fix also kind of applies to
+    // unnecessary_filter_map
+    let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
index 5585b10ab90..2d5403ce394 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
@@ -34,5 +34,11 @@ error: this `.filter_map` can be written more simply using `.map`
 LL |     let _ = (0..4).filter_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:155:14
+   |
+LL |     let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.rs b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
index a52390861b4..2c228fbbc95 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
@@ -21,3 +21,9 @@ fn main() {
 fn find_map_none_changes_item_type() -> Option<bool> {
     "".chars().find_map(|_| None)
 }
+
+fn issue11260() {
+    let y = Some(1);
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(y)); // different option, so can't be just `.find()`
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
index fb33c122fe3..3a995b41b17 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
@@ -34,5 +34,11 @@ error: this `.find_map` can be written more simply using `.map(..).next()`
 LL |     let _ = (0..4).find_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.find_map` can be written more simply using `.find`
+  --> $DIR/unnecessary_find_map.rs:27:14
+   |
+LL |     let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
index 276cd800b89..72d52c62355 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     1;
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = panic!();
     let _val = panic!("this always happens");
+    let _val: String = String::default();
+    let _val: u16 = 234;
+    let _val: u16 = 234;
+    let _val: u16 = { 234 };
+    let _val: u16 =  { 234 };
 
     panic!();
     panic!("this always happens");
+    String::default();
+    234;
+    234;
+    { 234 };
+     { 234 };
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
index 3065778d779..7d713ea205f 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     Some(1).expect("this never happens");
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = None::<()>.unwrap();
     let _val = None::<()>.expect("this always happens");
+    let _val: String = None.unwrap_or_default();
+    let _val: u16 = None.unwrap_or(234);
+    let _val: u16 = None.unwrap_or_else(|| 234);
+    let _val: u16 = None.unwrap_or_else(|| { 234 });
+    let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
 
     None::<()>.unwrap();
     None::<()>.expect("this always happens");
+    None::<String>.unwrap_or_default();
+    None::<u16>.unwrap_or(234);
+    None::<u16>.unwrap_or_else(|| 234);
+    None::<u16>.unwrap_or_else(|| { 234 });
+    None::<u16>.unwrap_or_else(|| -> u16 { 234 });
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 5823313b736..7f603d6ef58 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -48,13 +48,13 @@ LL +     1;
    |
 
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:20:16
+  --> $DIR/unnecessary_literal_unwrap.rs:21:16
    |
 LL |     let _val = None::<()>.unwrap();
    |                ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:21:16
+  --> $DIR/unnecessary_literal_unwrap.rs:22:16
    |
 LL |     let _val = None::<()>.expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,14 +64,68 @@ help: remove the `None` and `expect()`
 LL |     let _val = panic!("this always happens");
    |                ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:23:24
+   |
+LL |     let _val: String = None.unwrap_or_default();
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:24:21
+   |
+LL |     let _val: u16 = None.unwrap_or(234);
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     let _val: u16 = None.unwrap_or(234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:25:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| 234);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| 234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:26:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| { 234 });
+LL +     let _val: u16 = { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:27:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+LL +     let _val: u16 =  { 234 };
+   |
+
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:23:5
+  --> $DIR/unnecessary_literal_unwrap.rs:29:5
    |
 LL |     None::<()>.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:24:5
+  --> $DIR/unnecessary_literal_unwrap.rs:30:5
    |
 LL |     None::<()>.expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,8 +135,62 @@ help: remove the `None` and `expect()`
 LL |     panic!("this always happens");
    |     ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:31:5
+   |
+LL |     None::<String>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:32:5
+   |
+LL |     None::<u16>.unwrap_or(234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     None::<u16>.unwrap_or(234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| 234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| 234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| { 234 });
+LL +     { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+LL +      { 234 };
+   |
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:28:16
+  --> $DIR/unnecessary_literal_unwrap.rs:39:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +202,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:29:16
+  --> $DIR/unnecessary_literal_unwrap.rs:40:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -106,7 +214,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:30:16
+  --> $DIR/unnecessary_literal_unwrap.rs:41:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +225,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:31:16
+  --> $DIR/unnecessary_literal_unwrap.rs:42:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +236,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+  --> $DIR/unnecessary_literal_unwrap.rs:44:5
    |
 LL |     Ok::<_, ()>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -140,7 +248,7 @@ LL +     1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+  --> $DIR/unnecessary_literal_unwrap.rs:45:5
    |
 LL |     Ok::<_, ()>(1).expect("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -152,7 +260,7 @@ LL +     1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+  --> $DIR/unnecessary_literal_unwrap.rs:46:5
    |
 LL |     Ok::<_, ()>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +271,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:36:5
+  --> $DIR/unnecessary_literal_unwrap.rs:47:5
    |
 LL |     Ok::<_, ()>(1).expect_err("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +282,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:40:16
+  --> $DIR/unnecessary_literal_unwrap.rs:51:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -186,7 +294,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:41:16
+  --> $DIR/unnecessary_literal_unwrap.rs:52:16
    |
 LL |     let _val = Err::<(), _>(1).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +306,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:42:16
+  --> $DIR/unnecessary_literal_unwrap.rs:53:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +317,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:43:16
+  --> $DIR/unnecessary_literal_unwrap.rs:54:16
    |
 LL |     let _val = Err::<(), _>(1).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +328,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:45:5
+  --> $DIR/unnecessary_literal_unwrap.rs:56:5
    |
 LL |     Err::<(), _>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -232,7 +340,7 @@ LL +     1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:46:5
+  --> $DIR/unnecessary_literal_unwrap.rs:57:5
    |
 LL |     Err::<(), _>(1).expect_err("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +352,7 @@ LL +     1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:47:5
+  --> $DIR/unnecessary_literal_unwrap.rs:58:5
    |
 LL |     Err::<(), _>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -255,7 +363,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:48:5
+  --> $DIR/unnecessary_literal_unwrap.rs:59:5
    |
 LL |     Err::<(), _>(1).expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -266,7 +374,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:52:16
+  --> $DIR/unnecessary_literal_unwrap.rs:63:16
    |
 LL |     let _val = Some(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^
@@ -278,7 +386,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:53:16
+  --> $DIR/unnecessary_literal_unwrap.rs:64:16
    |
 LL |     let _val = Some(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -290,7 +398,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:54:16
+  --> $DIR/unnecessary_literal_unwrap.rs:65:16
    |
 LL |     let _val = Some(1).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +410,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:56:5
+  --> $DIR/unnecessary_literal_unwrap.rs:67:5
    |
 LL |     Some(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -314,7 +422,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:57:5
+  --> $DIR/unnecessary_literal_unwrap.rs:68:5
    |
 LL |     Some(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -326,7 +434,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:58:5
+  --> $DIR/unnecessary_literal_unwrap.rs:69:5
    |
 LL |     Some(1).unwrap_or_else(|| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -338,7 +446,7 @@ LL +     1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:62:16
+  --> $DIR/unnecessary_literal_unwrap.rs:73:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +458,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:63:16
+  --> $DIR/unnecessary_literal_unwrap.rs:74:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -362,7 +470,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:64:16
+  --> $DIR/unnecessary_literal_unwrap.rs:75:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +482,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:66:5
+  --> $DIR/unnecessary_literal_unwrap.rs:77:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -386,7 +494,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:67:5
+  --> $DIR/unnecessary_literal_unwrap.rs:78:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -398,7 +506,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:68:5
+  --> $DIR/unnecessary_literal_unwrap.rs:79:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -410,7 +518,7 @@ LL +     1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:82:22
+  --> $DIR/unnecessary_literal_unwrap.rs:93:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,7 +530,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:83:22
+  --> $DIR/unnecessary_literal_unwrap.rs:94:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -434,7 +542,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:84:22
+  --> $DIR/unnecessary_literal_unwrap.rs:95:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -446,7 +554,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:85:22
+  --> $DIR/unnecessary_literal_unwrap.rs:96:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -458,7 +566,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:86:22
+  --> $DIR/unnecessary_literal_unwrap.rs:97:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +578,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) };
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:87:22
+  --> $DIR/unnecessary_literal_unwrap.rs:98:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -482,7 +590,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_err_unchecked()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:88:22
+  --> $DIR/unnecessary_literal_unwrap.rs:99:22
    |
 LL |     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -493,5 +601,5 @@ LL -     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
 LL +     let _ = 123;
    |
 
-error: aborting due to 43 previous errors
+error: aborting due to 53 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
index 711fdce3962..41300aceb41 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
@@ -21,6 +21,8 @@ fn unwrap_option_none() {
     let val = None::<()>;
     let _val2 = val.unwrap();
     let _val2 = val.expect("this always happens");
+    let _val3: u8 = None.unwrap_or_default();
+    None::<()>.unwrap_or_default();
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
index feb9325b77a..2d1270d4717 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
@@ -95,509 +95,521 @@ help: remove the `None` and `expect()`
 LL |     let val = None::<()>;
    |               ^^^^^^^^^^
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:24:21
+   |
+LL |     let _val3: u8 = None.unwrap_or_default();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:25:5
+   |
+LL |     None::<()>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:32:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:33:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:45:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:46:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:53:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:54:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:66:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:67:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:73:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:74:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:84:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:85:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:91:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:92:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:102:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:103:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 50 previous errors
+error: aborting due to 52 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 69e46ab4736..1d188025e41 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -37,6 +37,23 @@ mod issue10459 {
     }
 }
 
+mod issue9695 {
+    use std::future::Future;
+
+    async fn f() {}
+    async fn f2() {}
+    async fn f3() {}
+
+    fn needs_async_fn<F: Future<Output = ()>>(_: fn() -> F) {}
+
+    fn test() {
+        let x = f;
+        needs_async_fn(x); // async needed in f
+        needs_async_fn(f2); // async needed in f2
+        f3(); // async not needed in f3
+    }
+}
+
 async fn foo() -> i32 {
     4
 }
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index ffae8366b88..8d9b72c4886 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -17,7 +17,15 @@ LL |             ready(()).await;
    = note: `-D clippy::unused-async` implied by `-D warnings`
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:40:1
+  --> $DIR/unused_async.rs:45:5
+   |
+LL |     async fn f3() {}
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the `async` from this function
+
+error: unused `async` for function with no await statements
+  --> $DIR/unused_async.rs:57:1
    |
 LL | / async fn foo() -> i32 {
 LL | |     4
@@ -27,7 +35,7 @@ LL | | }
    = help: consider removing the `async` from this function
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:51:5
+  --> $DIR/unused_async.rs:68:5
    |
 LL | /     async fn unused(&self) -> i32 {
 LL | |         1
@@ -36,5 +44,5 @@ LL | |     }
    |
    = help: consider removing the `async` from this function
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
index 08b89a18bbb..acdb96942ba 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
     empty_string.unwrap_or_default();
 }
 
+fn type_certainty(option: Option<Vec<u64>>) {
+    option.unwrap_or_default().push(1);
+
+    let option: std::option::Option<std::vec::Vec<u64>> = None;
+    option.unwrap_or_default().push(1);
+
+    let option: Option<Vec<u64>> = None;
+    option.unwrap_or_default().push(1);
+
+    let option = std::option::Option::<std::vec::Vec<u64>>::None;
+    option.unwrap_or_default().push(1);
+
+    let option = Option::<Vec<u64>>::None;
+    option.unwrap_or_default().push(1);
+
+    let option = std::option::Option::None::<std::vec::Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    let option = Option::None::<Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    let option = None::<Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    // should not be changed: type annotation with infer, unconcretized initializer
+    let option: Option<Vec<_>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = Option::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_default().push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_default();
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
index ad2a744908f..55ccd00e1a2 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
     empty_string.unwrap_or_else(|| "".to_string());
 }
 
+fn type_certainty(option: Option<Vec<u64>>) {
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option: std::option::Option<std::vec::Vec<u64>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option: Option<Vec<u64>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = std::option::Option::<std::vec::Vec<u64>>::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = Option::<Vec<u64>>::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = std::option::Option::None::<std::vec::Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = Option::None::<Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = None::<Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: type annotation with infer, unconcretized initializer
+    let option: Option<Vec<_>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = Option::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_else(Vec::new).push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_insert_with(Default::default);
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
index d2b9212223f..af662c6def7 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
@@ -1,40 +1,100 @@
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:48:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:48:14
    |
 LL |     with_new.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
    |
-   = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:62:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:62:23
    |
 LL |     with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:65:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:65:24
    |
 LL |     with_default_trait.unwrap_or_else(Default::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:68:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:68:23
    |
 LL |     with_default_type.unwrap_or_else(u64::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:71:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:71:23
    |
 LL |     with_default_type.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:74:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:74:18
    |
 LL |     empty_string.unwrap_or_else(|| "".to_string());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: aborting due to 6 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:78:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:81:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:84:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:87:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:90:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:93:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:96:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:99:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:115:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:132:32
+   |
+LL |     let _ = inner_map.entry(0).or_insert_with(Default::default);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index c40b71f6ca7..6856bb0ab37 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -9,6 +9,9 @@ allow-unauthenticated = [
 # See https://github.com/rust-lang/triagebot/wiki/Shortcuts
 [shortcut]
 
+# Have rustbot inform users about the *No Merge Policy*
+[no-merges]
+
 [autolabel."S-waiting-on-review"]
 new_pr = true
 
@@ -27,4 +30,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
     "@Alexendoo",
     "@dswij",
     "@Jarcho",
+    "@blyxyas",
+    "@Centri3",
 ]
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 452677d9146..042bb9bbd2c 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -10,10 +10,7 @@ on:
     branches:
       - 'master'
   schedule:
-    - cron: '6 6 * * *' # At 6:06 UTC every day.
-
-env:
-  CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
+    - cron: '11 5 * * *' # At 5:11 UTC every day.
 
 defaults:
   run:
@@ -21,10 +18,6 @@ defaults:
 
 jobs:
   build:
-    runs-on: ${{ matrix.os }}
-    env:
-      RUST_BACKTRACE: 1
-      HOST_TARGET: ${{ matrix.host_target }}
     strategy:
       fail-fast: false
       matrix:
@@ -35,6 +28,10 @@ jobs:
             host_target: x86_64-apple-darwin
           - os: windows-latest
             host_target: i686-pc-windows-msvc
+    runs-on: ${{ matrix.os }}
+    env:
+      RUST_BACKTRACE: 1
+      HOST_TARGET: ${{ matrix.host_target }}
     steps:
       - uses: actions/checkout@v3
 
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 4958c377215..1d5dd4d3f63 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-cec34a43b1b14f4e39363f3b283d7ac4f593ee81
+d150dbb067e66f351a0b33a54e7d4b464ef51e47
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 3b2d6f9608e..7723f06f296 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -227,10 +227,10 @@ pub(super) enum TransitionError {
     ChildAccessForbidden(Permission),
     /// A protector was triggered due to an invalid transition that loses
     /// too much permissions.
-    /// For example, if a protected tag goes from `Active` to `Frozen` due
-    /// to a foreign write this will produce a `ProtectedTransition(PermTransition(Active, Frozen))`.
+    /// For example, if a protected tag goes from `Active` to `Disabled` due
+    /// to a foreign write this will produce a `ProtectedDisabled(Active)`.
     /// This kind of error can only occur on foreign accesses.
-    ProtectedTransition(PermTransition),
+    ProtectedDisabled(Permission),
     /// Cannot deallocate because some tag in the allocation is strongly protected.
     /// This kind of error can only occur on deallocations.
     ProtectedDealloc,
@@ -302,7 +302,7 @@ impl TbError<'_> {
                 ));
                 (title, details, conflicting_tag_name)
             }
-            ProtectedTransition(transition) => {
+            ProtectedDisabled(before_disabled) => {
                 let conflicting_tag_name = "protected";
                 let access = cause.print_as_access(/* is_foreign */ true);
                 let details = vec![
@@ -310,12 +310,9 @@ impl TbError<'_> {
                         "the accessed tag {accessed} is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)"
                     ),
                     format!(
-                        "this {access} would cause the {conflicting_tag_name} tag {conflicting} to transition {transition}"
-                    ),
-                    format!(
-                        "this transition would be {loss}, which is not allowed for protected tags",
-                        loss = transition.summary(),
+                        "this {access} would cause the {conflicting_tag_name} tag {conflicting} (currently {before_disabled}) to become Disabled"
                     ),
+                    format!("protected tags must never be Disabled"),
                 ];
                 (title, details, conflicting_tag_name)
             }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 362070f1857..051b209da17 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -72,7 +72,12 @@ mod transition {
             // accesses, since the data is not being mutated. Hence the `{ .. }`
             res @ Reserved { .. } if !protected => res,
             Reserved { .. } => Frozen, // protected reserved
-            Active => Frozen,
+            Active =>
+                if protected {
+                    Disabled
+                } else {
+                    Frozen
+                },
             non_writeable @ (Frozen | Disabled) => non_writeable,
         })
     }
@@ -189,34 +194,9 @@ impl PermTransition {
         Permission { inner: self.from }
     }
 
-    /// Determines whether a transition that occured is compatible with the presence
-    /// of a Protector. This is not included in the `transition` functions because
-    /// it would distract from the few places where the transition is modified
-    /// because of a protector, but not forbidden.
-    ///
-    /// Note: this is not in charge of checking that there *is* a protector,
-    /// it should be used as
-    /// ```
-    /// let no_protector_error = if is_protected(tag) {
-    ///     transition.is_allowed_by_protector()
-    /// };
-    /// ```
-    pub fn is_allowed_by_protector(&self) -> bool {
-        assert!(self.is_possible());
-        match (self.from, self.to) {
-            _ if self.from == self.to => true,
-            // It is always a protector violation to not be readable anymore
-            (_, Disabled) => false,
-            // In the case of a `Reserved` under a protector, both transitions
-            // `Reserved => Active` and `Reserved => Frozen` can legitimately occur.
-            // The first is standard (Child Write), the second is for Foreign Writes
-            // on protected Reserved where we must ensure that the pointer is not
-            // written to in the future.
-            (Reserved { .. }, Active) | (Reserved { .. }, Frozen) => true,
-            // This pointer should have stayed writeable for the whole function
-            (Active, Frozen) => false,
-            _ => unreachable!("Transition {} should never be possible", self),
-        }
+    /// Determines if this transition would disable the permission.
+    pub fn produces_disabled(self) -> bool {
+        self.to == Disabled
     }
 }
 
@@ -298,14 +278,15 @@ pub mod diagnostics {
         ///
         /// This function assumes that its arguments apply to the same location
         /// and that they were obtained during a normal execution. It will panic otherwise.
-        /// - `err` cannot be a `ProtectedTransition(_)` of a noop transition, as those
-        /// never trigger protectors;
         /// - all transitions involved in `self` and `err` should be increasing
         /// (Reserved < Active < Frozen < Disabled);
         /// - between `self` and `err` the permission should also be increasing,
         /// so all permissions inside `err` should be greater than `self.1`;
         /// - `Active` and `Reserved` cannot cause an error due to insufficient permissions,
         /// so `err` cannot be a `ChildAccessForbidden(_)` of either of them;
+        /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
+        /// tag should not have been `Disabled` in the first place (if this occurs it means
+        /// we have unprotected tags that become protected)
         pub(in super::super) fn is_relevant(&self, err: TransitionError) -> bool {
             // NOTE: `super::super` is the visibility of `TransitionError`
             assert!(self.is_possible());
@@ -342,17 +323,16 @@ pub mod diagnostics {
                             unreachable!("permissions between self and err must be increasing"),
                     }
                 }
-                TransitionError::ProtectedTransition(forbidden) => {
-                    assert!(!forbidden.is_noop());
+                TransitionError::ProtectedDisabled(before_disabled) => {
                     // Show how we got to the starting point of the forbidden transition,
                     // but ignore what came before.
                     // This eliminates transitions like `Reserved -> Active`
                     // when the error is a `Frozen -> Disabled`.
-                    match (self.to, forbidden.from, forbidden.to) {
+                    match (self.to, before_disabled.inner) {
                         // We absolutely want to know where it was activated.
-                        (Active, Active, Frozen | Disabled) => true,
+                        (Active, Active) => true,
                         // And knowing where it became Frozen is also important.
-                        (Frozen, Frozen, Disabled) => true,
+                        (Frozen, Frozen) => true,
                         // If the error is a transition `Frozen -> Disabled`, then we don't really
                         // care whether before that was `Reserved -> Active -> Frozen` or
                         // `Reserved -> Frozen` or even `Frozen` directly.
@@ -360,27 +340,22 @@ pub mod diagnostics {
                         // - created as Frozen, then Frozen -> Disabled is forbidden
                         // - created as Reserved, later became Frozen, then Frozen -> Disabled is forbidden
                         // In both cases the `Reserved -> Active` part is inexistant or irrelevant.
-                        (Active, Frozen, Disabled) => false,
+                        (Active, Frozen) => false,
 
-                        // `Reserved -> Frozen` does not trigger protectors.
-                        (_, Reserved { .. }, Frozen) =>
-                            unreachable!("this transition cannot cause an error"),
+                        (_, Disabled) =>
+                            unreachable!(
+                                "permission that results in Disabled should not itself be Disabled in the first place"
+                            ),
                         // No transition has `Reserved` as its `.to` unless it's a noop.
-                        (Reserved { .. }, _, _) => unreachable!("self is a noop transition"),
-                        (_, Disabled, Disabled) | (_, Frozen, Frozen) | (_, Active, Active) =>
-                            unreachable!("err contains a noop transition"),
+                        (Reserved { .. }, _) => unreachable!("self is a noop transition"),
 
                         // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
                         // so permissions found must be increasing in the order
                         // `self.from < self.to <= forbidden.from < forbidden.to`.
-                        (Disabled, Reserved { .. } | Active | Frozen, _)
-                        | (Frozen, Reserved { .. } | Active, _)
-                        | (Active, Reserved { .. }, _) =>
+                        (Disabled, Reserved { .. } | Active | Frozen)
+                        | (Frozen, Reserved { .. } | Active)
+                        | (Active, Reserved { .. }) =>
                             unreachable!("permissions between self and err must be increasing"),
-                        (_, Disabled, Reserved { .. } | Active | Frozen)
-                        | (_, Frozen, Reserved { .. } | Active)
-                        | (_, Active, Reserved { .. }) =>
-                            unreachable!("permissions within err must be increasing"),
                     }
                 }
                 // We don't care because protectors evolve independently from
@@ -406,7 +381,7 @@ mod propagation_optimization_checks {
         pub use super::*;
         impl PermissionPriv {
             /// Enumerate all states
-            pub fn all() -> impl Iterator<Item = PermissionPriv> {
+            pub fn all() -> impl Iterator<Item = Self> {
                 vec![
                     Active,
                     Reserved { ty_is_freeze: true },
@@ -418,9 +393,15 @@ mod propagation_optimization_checks {
             }
         }
 
+        impl Permission {
+            pub fn all() -> impl Iterator<Item = Self> {
+                PermissionPriv::all().map(|inner| Self { inner })
+            }
+        }
+
         impl AccessKind {
             /// Enumerate all AccessKind.
-            pub fn all() -> impl Iterator<Item = AccessKind> {
+            pub fn all() -> impl Iterator<Item = Self> {
                 use AccessKind::*;
                 [Read, Write].into_iter()
             }
@@ -428,7 +409,7 @@ mod propagation_optimization_checks {
 
         impl AccessRelatedness {
             /// Enumerate all relative positions
-            pub fn all() -> impl Iterator<Item = AccessRelatedness> {
+            pub fn all() -> impl Iterator<Item = Self> {
                 use AccessRelatedness::*;
                 [This, StrictChildAccess, AncestorAccess, DistantAccess].into_iter()
             }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index 9e8b1e11899..355356b743a 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -19,6 +19,7 @@ use rustc_target::abi::Size;
 
 use crate::borrow_tracker::tree_borrows::{
     diagnostics::{self, NodeDebugInfo, TbError, TransitionError},
+    perms::PermTransition,
     unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap},
     Permission,
 };
@@ -28,17 +29,19 @@ use crate::*;
 /// Data for a single *location*.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub(super) struct LocationState {
-    /// This pointer's current permission
-    permission: Permission,
-    /// A location is initialized when it is child accessed for the first time,
-    /// and it then stays initialized forever.
-    /// Before initialization we still apply some preemptive transitions on
-    /// `permission` to know what to do in case it ever gets initialized,
-    /// but these can never cause any immediate UB. There can however be UB
-    /// the moment we attempt to initialize (i.e. child-access) because some
-    /// foreign access done between the creation and the initialization is
-    /// incompatible with child accesses.
+    /// A location is initialized when it is child-accessed for the first time (and the initial
+    /// retag initializes the location for the range covered by the type), and it then stays
+    /// initialized forever.
+    /// For initialized locations, "permission" is the current permission. However, for
+    /// uninitialized locations, we still need to track the "future initial permission": this will
+    /// start out to be `default_initial_perm`, but foreign accesses need to be taken into account.
+    /// Crucially however, while transitions to `Disabled` would usually be UB if this location is
+    /// protected, that is *not* the case for uninitialized locations. Instead we just have a latent
+    /// "future initial permission" of `Disabled`, causing UB only if an access is ever actually
+    /// performed.
     initialized: bool,
+    /// This pointer's current permission / future initial permission.
+    permission: Permission,
     /// Strongest foreign access whose effects have already been applied to
     /// this node and all its children since the last child access.
     /// This is `None` if the most recent access is a child access,
@@ -69,6 +72,104 @@ impl LocationState {
     pub fn permission(&self) -> Permission {
         self.permission
     }
+
+    /// Apply the effect of an access to one location, including
+    /// - applying `Permission::perform_access` to the inner `Permission`,
+    /// - emitting protector UB if the location is initialized,
+    /// - updating the initialized status (child accesses produce initialized locations).
+    fn perform_access(
+        &mut self,
+        access_kind: AccessKind,
+        rel_pos: AccessRelatedness,
+        protected: bool,
+    ) -> Result<PermTransition, TransitionError> {
+        let old_perm = self.permission;
+        let transition = Permission::perform_access(access_kind, rel_pos, old_perm, protected)
+            .ok_or(TransitionError::ChildAccessForbidden(old_perm))?;
+        // Why do only initialized locations cause protector errors?
+        // Consider two mutable references `x`, `y` into disjoint parts of
+        // the same allocation. A priori, these may actually both be used to
+        // access the entire allocation, as long as only reads occur. However,
+        // a write to `y` needs to somehow record that `x` can no longer be used
+        // on that location at all. For these uninitialized locations (i.e., locations
+        // that haven't been accessed with `x` yet), we track the "future initial state":
+        // it defaults to whatever the initial state of the tag is,
+        // but the access to `y` moves that "future initial state" of `x` to `Disabled`.
+        // However, usually a `Reserved -> Disabled` transition would be UB due to the protector!
+        // So clearly protectors shouldn't fire for such "future initial state" transitions.
+        //
+        // See the test `two_mut_protected_same_alloc` in `tests/pass/tree_borrows/tree-borrows.rs`
+        // for an example of safe code that would be UB if we forgot to check `self.initialized`.
+        if protected && self.initialized && transition.produces_disabled() {
+            return Err(TransitionError::ProtectedDisabled(old_perm));
+        }
+        self.permission = transition.applied(old_perm).unwrap();
+        self.initialized |= !rel_pos.is_foreign();
+        Ok(transition)
+    }
+
+    // Helper to optimize the tree traversal.
+    // The optimization here consists of observing thanks to the tests
+    // `foreign_read_is_noop_after_write` and `all_transitions_idempotent`,
+    // that there are actually just three possible sequences of events that can occur
+    // in between two child accesses that produce different results.
+    //
+    // Indeed,
+    // - applying any number of foreign read accesses is the same as applying
+    //   exactly one foreign read,
+    // - applying any number of foreign read or write accesses is the same
+    //   as applying exactly one foreign write.
+    // therefore the three sequences of events that can produce different
+    // outcomes are
+    // - an empty sequence (`self.latest_foreign_access = None`)
+    // - a nonempty read-only sequence (`self.latest_foreign_access = Some(Read)`)
+    // - a nonempty sequence with at least one write (`self.latest_foreign_access = Some(Write)`)
+    //
+    // This function not only determines if skipping the propagation right now
+    // is possible, it also updates the internal state to keep track of whether
+    // the propagation can be skipped next time.
+    // It is a performance loss not to call this function when a foreign access occurs.
+    // It is unsound not to call this function when a child access occurs.
+    fn skip_if_known_noop(
+        &mut self,
+        access_kind: AccessKind,
+        rel_pos: AccessRelatedness,
+    ) -> ContinueTraversal {
+        if rel_pos.is_foreign() {
+            let new_access_noop = match (self.latest_foreign_access, access_kind) {
+                // Previously applied transition makes the new one a guaranteed
+                // noop in the two following cases:
+                // (1) justified by `foreign_read_is_noop_after_write`
+                (Some(AccessKind::Write), AccessKind::Read) => true,
+                // (2) justified by `all_transitions_idempotent`
+                (Some(old), new) if old == new => true,
+                // In all other cases there has been a recent enough
+                // child access that the effects of the new foreign access
+                // need to be applied to this subtree.
+                _ => false,
+            };
+            if new_access_noop {
+                // Abort traversal if the new transition is indeed guaranteed
+                // to be noop.
+                // No need to update `self.latest_foreign_access`,
+                // the type of the current streak among nonempty read-only
+                // or nonempty with at least one write has not changed.
+                ContinueTraversal::SkipChildren
+            } else {
+                // Otherwise propagate this time, and also record the
+                // access that just occurred so that we can skip the propagation
+                // next time.
+                self.latest_foreign_access = Some(access_kind);
+                ContinueTraversal::Recurse
+            }
+        } else {
+            // A child access occurred, this breaks the streak of foreign
+            // accesses in a row and the sequence since the previous child access
+            // is now empty.
+            self.latest_foreign_access = None;
+            ContinueTraversal::Recurse
+        }
+    }
 }
 
 /// Tree structure with both parents and children since we want to be
@@ -387,11 +488,15 @@ impl<'tcx> Tree {
         Ok(())
     }
 
-    /// Maps the following propagation procedure to each range:
-    /// - initialize if needed;
-    /// - compute new state after transition;
-    /// - check that there is no protector that would forbid this;
-    /// - record this specific location as accessed.
+    /// Map the per-node and per-location `LocationState::perform_access`
+    /// to each location of `access_range`, on every tag of the allocation.
+    ///
+    /// `LocationState::perform_access` will take care of raising transition
+    /// errors and updating the `initialized` status of each location,
+    /// this traversal adds to that:
+    /// - inserting into the map locations that do not exist yet,
+    /// - trimming the traversal,
+    /// - recording the history.
     pub fn perform_access(
         &mut self,
         access_kind: AccessKind,
@@ -411,55 +516,16 @@ impl<'tcx> Tree {
                         let old_state =
                             perm.or_insert_with(|| LocationState::new(node.default_initial_perm));
 
-                        // Optimize the tree traversal.
-                        // The optimization here consists of observing thanks to the tests
-                        // `foreign_read_is_noop_after_write` and `all_transitions_idempotent`
-                        // that if we apply twice in a row the effects of a foreign access
-                        // we can skip some branches.
-                        // "two foreign accesses in a row" occurs when `perm.latest_foreign_access` is `Some(_)`
-                        // AND the `rel_pos` of the current access corresponds to a foreign access.
-                        if rel_pos.is_foreign() {
-                            let new_access_noop =
-                                match (old_state.latest_foreign_access, access_kind) {
-                                    // Previously applied transition makes the new one a guaranteed
-                                    // noop in the two following cases:
-                                    // (1) justified by `foreign_read_is_noop_after_write`
-                                    (Some(AccessKind::Write), AccessKind::Read) => true,
-                                    // (2) justified by `all_transitions_idempotent`
-                                    (Some(old), new) if old == new => true,
-                                    // In all other cases there has been a recent enough
-                                    // child access that the effects of the new foreign access
-                                    // need to be applied to this subtree.
-                                    _ => false,
-                                };
-                            if new_access_noop {
-                                // Abort traversal if the new transition is indeed guaranteed
-                                // to be noop.
-                                return Ok(ContinueTraversal::SkipChildren);
-                            } else {
-                                // Otherwise propagate this time, and also record the
-                                // access that just occurred so that we can skip the propagation
-                                // next time.
-                                old_state.latest_foreign_access = Some(access_kind);
-                            }
-                        } else {
-                            // A child access occurred, this breaks the streak of "two foreign
-                            // accesses in a row" and we reset this field.
-                            old_state.latest_foreign_access = None;
+                        match old_state.skip_if_known_noop(access_kind, rel_pos) {
+                            ContinueTraversal::SkipChildren =>
+                                return Ok(ContinueTraversal::SkipChildren),
+                            _ => {}
                         }
 
-                        let old_perm = old_state.permission;
                         let protected = global.borrow().protected_tags.contains_key(&node.tag);
                         let transition =
-                            Permission::perform_access(access_kind, rel_pos, old_perm, protected)
-                                .ok_or(TransitionError::ChildAccessForbidden(old_perm))?;
-                        if protected
-                            // Can't trigger Protector on uninitialized locations
-                            && old_state.initialized
-                            && !transition.is_allowed_by_protector()
-                        {
-                            return Err(TransitionError::ProtectedTransition(transition));
-                        }
+                            old_state.perform_access(access_kind, rel_pos, protected)?;
+
                         // Record the event as part of the history
                         if !transition.is_noop() {
                             node.debug_info.history.push(diagnostics::Event {
@@ -470,10 +536,7 @@ impl<'tcx> Tree {
                                 transition_range: perms_range.clone(),
                                 span,
                             });
-                            old_state.permission =
-                                transition.applied(old_state.permission).unwrap();
                         }
-                        old_state.initialized |= !rel_pos.is_foreign();
                         Ok(ContinueTraversal::Recurse)
                     },
                     |args: ErrHandlerArgs<'_, TransitionError>| -> InterpError<'tcx> {
@@ -602,3 +665,57 @@ impl AccessRelatedness {
         }
     }
 }
+
+#[cfg(test)]
+mod commutation_tests {
+    use super::*;
+    impl LocationState {
+        pub fn all_without_access() -> impl Iterator<Item = Self> {
+            Permission::all().flat_map(|permission| {
+                [false, true].into_iter().map(move |initialized| {
+                    Self { permission, initialized, latest_foreign_access: None }
+                })
+            })
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    // Exhaustive check that for any starting configuration loc,
+    // for any two read accesses r1 and r2, if `loc + r1 + r2` is not UB
+    // and results in `loc'`, then `loc + r2 + r1` is also not UB and results
+    // in the same final state `loc'`.
+    // This lets us justify arbitrary read-read reorderings.
+    fn all_read_accesses_commute() {
+        let kind = AccessKind::Read;
+        // Two of the four combinations of `AccessRelatedness` are trivial,
+        // but we might as well check them all.
+        for rel1 in AccessRelatedness::all() {
+            for rel2 in AccessRelatedness::all() {
+                // Any protector state works, but we can't move reads across function boundaries
+                // so the two read accesses occur under the same protector.
+                for &protected in &[true, false] {
+                    for loc in LocationState::all_without_access() {
+                        // Apply 1 then 2. Failure here means that there is UB in the source
+                        // and we skip the check in the target.
+                        let mut loc12 = loc;
+                        let Ok(_) = loc12.perform_access(kind, rel1, protected) else { continue; };
+                        let Ok(_) = loc12.perform_access(kind, rel2, protected) else { continue; };
+
+                        // If 1 followed by 2 succeeded, then 2 followed by 1 must also succeed...
+                        let mut loc21 = loc;
+                        loc21.perform_access(kind, rel2, protected).unwrap();
+                        loc21.perform_access(kind, rel1, protected).unwrap();
+
+                        // ... and produce the same final result.
+                        assert_eq!(
+                            loc12, loc21,
+                            "Read accesses {:?} followed by {:?} do not commute !",
+                            rel1, rel2
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/mono_hash_map.rs b/src/tools/miri/src/mono_hash_map.rs
index 45057632df9..81b3153517f 100644
--- a/src/tools/miri/src/mono_hash_map.rs
+++ b/src/tools/miri/src/mono_hash_map.rs
@@ -2,7 +2,7 @@
 //! otherwise mutated. We also box items in the map. This means we can safely provide
 //! shared references into existing items in the `FxHashMap`, because they will not be dropped
 //! (from being removed) or moved (because they are boxed).
-//! The API is is completely tailored to what `memory.rs` needs. It is still in
+//! The API is completely tailored to what `memory.rs` needs. It is still in
 //! a separate file to minimize the amount of code that has to care about the unsafety.
 
 use std::borrow::Borrow;
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index e89b2e01a39..9f4bb37a469 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -194,14 +194,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let filename_alloc =
                     this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
 
-                this.write_immediate(
-                    name_alloc.to_ref(this),
-                    &this.project_field(&dest, 0)?,
-                )?;
-                this.write_immediate(
-                    filename_alloc.to_ref(this),
-                    &this.project_field(&dest, 1)?,
-                )?;
+                this.write_immediate(name_alloc.to_ref(this), &this.project_field(&dest, 0)?)?;
+                this.write_immediate(filename_alloc.to_ref(this), &this.project_field(&dest, 1)?)?;
             }
             1 => {
                 this.write_scalar(
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 6667c4d751f..935447fd89d 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -156,10 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
         })?;
-        this.write_scalar(
-            Scalar::from_i64(qpc),
-            &this.deref_operand(lpPerformanceCount_op)?,
-        )?;
+        this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?)?;
         Ok(Scalar::from_i32(-1)) // return non-zero on success
     }
 
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 3673ca5aee3..5141b29b683 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -86,7 +86,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "_NSGetEnviron" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.write_pointer(
-                    this.machine.env_vars.environ.as_ref().expect("machine must be initialized").ptr,
+                    this.machine
+                        .env_vars
+                        .environ
+                        .as_ref()
+                        .expect("machine must be initialized")
+                        .ptr,
                     dest,
                 )?;
             }
@@ -139,10 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 if written {
                     this.write_null(dest)?;
                 } else {
-                    this.write_scalar(
-                        Scalar::from_u32(size_needed.try_into().unwrap()),
-                        &bufsize,
-                    )?;
+                    this.write_scalar(Scalar::from_u32(size_needed.try_into().unwrap()), &bufsize)?;
                     this.write_int(-1, dest)?;
                 }
             }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index 428581801d9..0aeb8ae95a7 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -867,9 +867,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         cond_get_clock_id(this, cond_op)?;
 
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
-        this.write_uninit(
-            &this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?,
-        )?;
+        this.write_uninit(&this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
         // FIXME: delete interpreter state associated with this condvar.
 
         Ok(0)
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index c26954da272..fa17923446f 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -191,6 +191,8 @@ regexes! {
     // erase borrow tags
     "<[0-9]+>"                       => "<TAG>",
     "<[0-9]+="                       => "<TAG=",
+    // normalize width of Tree Borrows diagnostic borders (which otherwise leak borrow tag info)
+    "(─{50})─+"                      => "$1",
     // erase whitespace that differs between platforms
     r" +at (.*\.rs)"                 => " at $1",
     // erase generics in backtraces
diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr
index 4102c718af8..106e5c19bf2 100644
--- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr
@@ -6,8 +6,8 @@ LL |         ptr::write(dest, src);
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Frozen to Disabled
-   = help: this transition would be a loss of read permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/aliasing_mut4.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
index 1d1ed820324..1ecd6620806 100644
--- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
@@ -6,8 +6,8 @@ LL |     *y
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> to transition from Active to Frozen
-   = help: this transition would be a loss of write permissions, which is not allowed for protected tags
+   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/box_noalias_violation.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
index 7308d045d19..64e08f545e3 100644
--- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { *y = 2 };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Active to Disabled
-   = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/illegal_write6.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr
index ee64a66cc21..66f7f1788e4 100644
--- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { *x = 0 };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Frozen to Disabled
-   = help: this transition would be a loss of read permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/invalidate_against_protector2.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr
index e217170afb9..ef807d7362e 100644
--- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { *x = 0 };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Frozen to Disabled
-   = help: this transition would be a loss of read permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/invalidate_against_protector3.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
index 00b2708a651..f26fc6cbaae 100644
--- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> to transition from Frozen to Disabled
-   = help: this transition would be a loss of read permissions, which is not allowed for protected tags
+   = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/newtype_pair_retagging.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
index aed2e7abebc..687c72d574d 100644
--- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> to transition from Frozen to Disabled
-   = help: this transition would be a loss of read permissions, which is not allowed for protected tags
+   = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/newtype_retagging.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/concurrency/unwind_top_of_stack.stderr b/src/tools/miri/tests/fail/concurrency/unwind_top_of_stack.stderr
index 98db33e3206..ceb5955922a 100644
--- a/src/tools/miri/tests/fail/concurrency/unwind_top_of_stack.stderr
+++ b/src/tools/miri/tests/fail/concurrency/unwind_top_of_stack.stderr
@@ -1,4 +1,5 @@
-thread '<unnamed>' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC
+thread '<unnamed>' panicked at $DIR/unwind_top_of_stack.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: Undefined Behavior: unwinding past the topmost frame of the stack
   --> $DIR/unwind_top_of_stack.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
index 35c02cc2ebd..8393b80f25b 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { ptr.write(S(0)) };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Active to Disabled
-   = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/arg_inplace_mutate.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
index cbd76c38f62..5af4856bbe3 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { ptr.read() };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> to transition from Active to Frozen
-   = help: this transition would be a loss of write permissions, which is not allowed for protected tags
+   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/arg_inplace_observe_during.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr
index 7f87ec6f3bb..f181f90abd3 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind1.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
   --> $DIR/exported_symbol_bad_unwind1.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
index e1631471ae2..bf5199307f6 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
index e1631471ae2..bf5199307f6 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr
index b23c05a5303..c774bd4dd91 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr
index c2c9de3f4ee..c491a904a10 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr
@@ -6,8 +6,8 @@ LL |     unsafe { ptr.read() };
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> to transition from Active to Frozen
-   = help: this transition would be a loss of write permissions, which is not allowed for protected tags
+   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/return_pointer_aliasing.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr
index 5d7f01f4786..18438c13b21 100644
--- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr
+++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/bad_unwind.rs:LL:CC
+thread 'main' panicked at $DIR/bad_unwind.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
   --> $DIR/bad_unwind.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr
index b6ac56f15d4..8e008da75ee 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/double_panic.stderr
@@ -1,6 +1,8 @@
-thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC
+thread 'main' panicked at $DIR/double_panic.rs:LL:CC:
+first
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC
+thread 'main' panicked at $DIR/double_panic.rs:LL:CC:
+second
 stack backtrace:
 error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/double_panic.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr
index f8307c0c23b..47ec710052a 100644
--- a/src/tools/miri/tests/fail/panic/no_std.stderr
+++ b/src/tools/miri/tests/fail/panic/no_std.stderr
@@ -1,4 +1,5 @@
-panicked at 'blarg I am dead', $DIR/no_std.rs:LL:CC
+panicked at $DIR/no_std.rs:LL:CC:
+blarg I am dead
 error: abnormal termination: the program aborted execution
   --> $DIR/no_std.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
index d9303fd0d06..404777344d7 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'panicking from libstd', $DIR/panic_abort1.rs:LL:CC
+thread 'main' panicked at $DIR/panic_abort1.rs:LL:CC:
+panicking from libstd
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
index 54cbc9b5f6d..5512d145c6b 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at '42-panicking from libstd', $DIR/panic_abort2.rs:LL:CC
+thread 'main' panicked at $DIR/panic_abort2.rs:LL:CC:
+42-panicking from libstd
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
index 64eea47b14b..9fdccd4e59e 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'panicking from libcore', $DIR/panic_abort3.rs:LL:CC
+thread 'main' panicked at $DIR/panic_abort3.rs:LL:CC:
+panicking from libcore
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
index 21beb100645..3c9557ca4ab 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at '42-panicking from libcore', $DIR/panic_abort4.rs:LL:CC
+thread 'main' panicked at $DIR/panic_abort4.rs:LL:CC:
+42-panicking from libcore
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/thread_local_const_drop_panic.stderr b/src/tools/miri/tests/fail/panic/thread_local_const_drop_panic.stderr
index 47962e44adf..550d009607d 100644
--- a/src/tools/miri/tests/fail/panic/thread_local_const_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/thread_local_const_drop_panic.stderr
@@ -1,4 +1,5 @@
-thread $NAME panicked at 'ow', $DIR/thread_local_const_drop_panic.rs:LL:CC
+thread $NAME panicked at $DIR/thread_local_const_drop_panic.rs:LL:CC:
+ow
 fatal runtime error: thread local panicked on drop
 error: abnormal termination: the program aborted execution
 
diff --git a/src/tools/miri/tests/fail/panic/thread_local_drop_panic.stderr b/src/tools/miri/tests/fail/panic/thread_local_drop_panic.stderr
index 2a56e2b9c87..3d6c41faabc 100644
--- a/src/tools/miri/tests/fail/panic/thread_local_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/thread_local_drop_panic.stderr
@@ -1,4 +1,5 @@
-thread $NAME panicked at 'ow', $DIR/thread_local_drop_panic.rs:LL:CC
+thread $NAME panicked at $DIR/thread_local_drop_panic.rs:LL:CC:
+ow
 fatal runtime error: thread local panicked on drop
 error: abnormal termination: the program aborted execution
 
diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr
index d73e23a53d0..4f73b599a3f 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.stderr
+++ b/src/tools/miri/tests/fail/terminate-terminator.stderr
@@ -1,6 +1,7 @@
 warning: You have explicitly enabled MIR optimizations, overriding Miri's default which is to completely disable them. Any optimizations may hide UB that Miri would otherwise detect, and it is not necessarily possible to predict what kind of UB will be missed. If you are enabling optimizations to make Miri run faster, we advise using cfg(miri) to shrink your workload instead. The performance benefit of enabling MIR optimizations is usually marginal at best.
 
-thread 'main' panicked at 'explicit panic', $DIR/terminate-terminator.rs:LL:CC
+thread 'main' panicked at $DIR/terminate-terminator.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/terminate-terminator.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr
index 0feafb1a71e..8b3bf8414db 100644
--- a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr
@@ -6,8 +6,8 @@ LL |     *y.add(3) = 42;
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> to transition from Reserved to Disabled
-   = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (currently Reserved) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/outside-range.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
index 5e910779621..769769d957d 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
@@ -1,4 +1,4 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -7,7 +7,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Re*|        │ └─┬──<TAG=caller:x>
 | Re*|        │   └────<TAG=callee:x> Strongly protected
 | Re*|        └────<TAG=y, callee:y, caller:y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) is forbidden
   --> $DIR/cell-protected-write.rs:LL:CC
    |
@@ -16,8 +16,8 @@ LL |             *y = 1;
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (callee:x) to transition from Reserved to Disabled
-   = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/cell-protected-write.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr
index e28aac306cd..f7e9fb9e3c3 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr
@@ -1,4 +1,4 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -7,7 +7,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Res|        │ └─┬──<TAG=caller:x>
 | Res|        │   └────<TAG=callee:x> Strongly protected
 | Res|        └────<TAG=y, callee:y, caller:y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) is forbidden
   --> $DIR/int-protected-write.rs:LL:CC
    |
@@ -16,8 +16,8 @@ LL |             *y = 0;
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: the accessed tag <TAG> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (callee:x) to transition from Reserved to Disabled
-   = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags
+   = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled
+   = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/int-protected-write.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
index 52a1879cb5f..daa4a808df9 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/unwind-action-terminate.rs:LL:CC
+thread 'main' panicked at $DIR/unwind-action-terminate.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/unwind-action-terminate.rs:LL:CC
diff --git a/src/tools/miri/tests/panic/div-by-zero-2.stderr b/src/tools/miri/tests/panic/div-by-zero-2.stderr
index 538d8711365..0f088ddd1a5 100644
--- a/src/tools/miri/tests/panic/div-by-zero-2.stderr
+++ b/src/tools/miri/tests/panic/div-by-zero-2.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:LL:CC
+thread 'main' panicked at $DIR/div-by-zero-2.rs:LL:CC:
+attempt to divide by zero
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr
index bff897775e8..acc0e58885f 100644
--- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr
+++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr
@@ -1,4 +1,7 @@
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC
-thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC
+thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:
+explicit panic
+thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:
+explicit panic
diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr
index 4c6deaeccf6..2bccb60352e 100644
--- a/src/tools/miri/tests/panic/oob_subslice.stderr
+++ b/src/tools/miri/tests/panic/oob_subslice.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'range end index 5 out of range for slice of length 4', $DIR/oob_subslice.rs:LL:CC
+thread 'main' panicked at $DIR/oob_subslice.rs:LL:CC:
+range end index 5 out of range for slice of length 4
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr
index 21e434d873f..2cff81c58af 100644
--- a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr
+++ b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:LL:CC
+thread 'main' panicked at $DIR/overflowing-lsh-neg.rs:LL:CC:
+attempt to shift left with overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr
index fd04bf1bd4e..13117df5fc3 100644
--- a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr
+++ b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:LL:CC
+thread 'main' panicked at $DIR/overflowing-rsh-1.rs:LL:CC:
+attempt to shift right with overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr
index eb568e4d742..986a66f8991 100644
--- a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr
+++ b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:LL:CC
+thread 'main' panicked at $DIR/overflowing-rsh-2.rs:LL:CC:
+attempt to shift right with overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/panic1.stderr b/src/tools/miri/tests/panic/panic1.stderr
index 0f4535e6792..4eb4244d747 100644
--- a/src/tools/miri/tests/panic/panic1.stderr
+++ b/src/tools/miri/tests/panic/panic1.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:LL:CC
+thread 'main' panicked at $DIR/panic1.rs:LL:CC:
+panicking from libstd
 stack backtrace:
    0: std::panicking::begin_panic_handler
  at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/panic/panic2.stderr b/src/tools/miri/tests/panic/panic2.stderr
index c192ca3f64c..bee1af2bef6 100644
--- a/src/tools/miri/tests/panic/panic2.stderr
+++ b/src/tools/miri/tests/panic/panic2.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:LL:CC
+thread 'main' panicked at $DIR/panic2.rs:LL:CC:
+42-panicking from libstd
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/panic3.stderr b/src/tools/miri/tests/panic/panic3.stderr
index 0ce4a37fd51..8dac000d291 100644
--- a/src/tools/miri/tests/panic/panic3.stderr
+++ b/src/tools/miri/tests/panic/panic3.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:LL:CC
+thread 'main' panicked at $DIR/panic3.rs:LL:CC:
+panicking from libcore
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/panic4.stderr b/src/tools/miri/tests/panic/panic4.stderr
index 82df953b61c..13437fe7f07 100644
--- a/src/tools/miri/tests/panic/panic4.stderr
+++ b/src/tools/miri/tests/panic/panic4.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:LL:CC
+thread 'main' panicked at $DIR/panic4.rs:LL:CC:
+42-panicking from libcore
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/transmute_fat2.stderr b/src/tools/miri/tests/panic/transmute_fat2.stderr
index f497ab67255..1f09a2c1a08 100644
--- a/src/tools/miri/tests/panic/transmute_fat2.stderr
+++ b/src/tools/miri/tests/panic/transmute_fat2.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:LL:CC
+thread 'main' panicked at $DIR/transmute_fat2.rs:LL:CC:
+index out of bounds: the len is 0 but the index is 0
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr
index a49dbdae58a..4db1e290961 100644
--- a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr
+++ b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function `foo` on $OS', $DIR/unsupported_foreign_function.rs:LL:CC
+thread 'main' panicked at $DIR/unsupported_foreign_function.rs:LL:CC:
+unsupported Miri functionality: can't call foreign function `foo` on $OS
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/panic/unsupported_syscall.stderr b/src/tools/miri/tests/panic/unsupported_syscall.stderr
index 90aa5a90736..40ba6671d5b 100644
--- a/src/tools/miri/tests/panic/unsupported_syscall.stderr
+++ b/src/tools/miri/tests/panic/unsupported_syscall.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:LL:CC
+thread 'main' panicked at $DIR/unsupported_syscall.rs:LL:CC:
+unsupported Miri functionality: can't execute syscall with ID 0
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/pass/align_repeat_into_packed_field.rs b/src/tools/miri/tests/pass/align_repeat_into_packed_field.rs
new file mode 100644
index 00000000000..3affb204205
--- /dev/null
+++ b/src/tools/miri/tests/pass/align_repeat_into_packed_field.rs
@@ -0,0 +1,22 @@
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[repr(packed)]
+struct S { field: [u32; 2] }
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn test() { mir! {
+    let s: S;
+    {
+        // Store a repeat expression directly into a field of a packed struct.
+        s.field = [0; 2];
+        Return()
+    }
+} }
+
+fn main() {
+    // Run this a bunch of time to make sure it doesn't pass by chance.
+    for _ in 0..20 {
+        test();
+    }
+}
diff --git a/src/tools/miri/tests/pass/issues/issue-miri-1925.rs b/src/tools/miri/tests/pass/align_repeat_into_well_aligned_array.rs
index 86556813491..735251039f7 100644
--- a/src/tools/miri/tests/pass/issues/issue-miri-1925.rs
+++ b/src/tools/miri/tests/pass/align_repeat_into_well_aligned_array.rs
@@ -4,6 +4,8 @@ use std::mem::size_of;
 
 fn main() {
     let mut a = Params::new();
+    // The array itself here happens to be quite well-aligned, but not all its elements have that
+    // large alignment and we better make sure that is still accepted by Miri.
     a.key_block = [0; BLOCKBYTES];
 }
 
diff --git a/src/tools/miri/tests/pass/concurrency/simple.stderr b/src/tools/miri/tests/pass/concurrency/simple.stderr
index 028cc0fb736..33d6b6841ad 100644
--- a/src/tools/miri/tests/pass/concurrency/simple.stderr
+++ b/src/tools/miri/tests/pass/concurrency/simple.stderr
@@ -1,3 +1,5 @@
-thread '<unnamed>' panicked at 'Hello!', $DIR/simple.rs:LL:CC
+thread '<unnamed>' panicked at $DIR/simple.rs:LL:CC:
+Hello!
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:LL:CC
+thread 'childthread' panicked at $DIR/simple.rs:LL:CC:
+Hello, world!
diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs
index a6a4a06f860..8c6eeab2219 100644
--- a/src/tools/miri/tests/pass/intrinsics.rs
+++ b/src/tools/miri/tests/pass/intrinsics.rs
@@ -3,7 +3,7 @@
 //! Tests for various intrinsics that do not fit anywhere else.
 
 use std::intrinsics;
-use std::mem::{size_of, size_of_val, size_of_val_raw, discriminant};
+use std::mem::{discriminant, size_of, size_of_val, size_of_val_raw};
 
 struct Bomb;
 
diff --git a/src/tools/miri/tests/pass/panic/catch_panic.stderr b/src/tools/miri/tests/pass/panic/catch_panic.stderr
index f43434582a2..aa005590db3 100644
--- a/src/tools/miri/tests/pass/panic/catch_panic.stderr
+++ b/src/tools/miri/tests/pass/panic/catch_panic.stderr
@@ -1,24 +1,35 @@
-thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Hello from panic: std
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 Caught panic message (&str): Hello from panic: std
-thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Hello from panic: 1
 Caught panic message (String): Hello from panic: 1
-thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Hello from panic: 2
 Caught panic message (String): Hello from panic: 2
-thread 'main' panicked at 'Box<dyn Any>', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Box<dyn Any>
 Failed to get caught panic message.
-thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Hello from panic: core
 Caught panic message (&str): Hello from panic: core
-thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+Hello from panic: 5
 Caught panic message (String): Hello from panic: 5
-thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+index out of bounds: the len is 3 but the index is 4
 Caught panic message (String): index out of bounds: the len is 3 but the index is 4
-thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+attempt to divide by zero
 Caught panic message (&str): attempt to divide by zero
-thread 'main' panicked at 'align_offset: align is not a power-of-two', RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC
+thread 'main' panicked at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC:
+align_offset: align is not a power-of-two
 Caught panic message (&str): align_offset: align is not a power-of-two
-thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+assertion failed: false
 Caught panic message (&str): assertion failed: false
-thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC
+thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
+assertion failed: false
 Caught panic message (&str): assertion failed: false
 Success!
diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr
index fd8fabc89cc..0bb3dcd8d24 100644
--- a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr
+++ b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr
@@ -1,10 +1,12 @@
 Thread 1 starting, will block on mutex
 Thread 1 reported it has started
-thread '<unnamed>' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:LL:CC
+thread '<unnamed>' panicked at $DIR/concurrent-panic.rs:LL:CC:
+panic in thread 2
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 Thread 2 blocking on thread 1
 Thread 2 reported it has started
 Unlocking mutex
-thread '<unnamed>' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:LL:CC
+thread '<unnamed>' panicked at $DIR/concurrent-panic.rs:LL:CC:
+panic in thread 1
 Thread 1 has exited
 Thread 2 has exited
diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr
index 4e2593242df..4684beb3338 100644
--- a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr
+++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr
@@ -1,4 +1,6 @@
-thread 'main' panicked at 'once', $DIR/nested_panic_caught.rs:LL:CC
+thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC:
+once
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'twice', $DIR/nested_panic_caught.rs:LL:CC
+thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC:
+twice
 stack backtrace:
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
index 1eab4685a35..f464e0b4f49 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
@@ -1,12 +1,12 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Re*|      └────<TAG=data, x, y>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └────<TAG=data, x, y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr b/src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr
index c20da1a593f..265f6dfc9c8 100644
--- a/src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr
@@ -1,11 +1,11 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Res|      └─┬──<TAG=data>
 | Res|        └────<TAG=x>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -13,8 +13,8 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Res|        └─┬──<TAG=x>
 | Res|          └─┬──<TAG=caller:x>
 | Res|            └────<TAG=callee:x> Strongly protected
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -23,8 +23,8 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Res|        │ └─┬──<TAG=caller:x>
 | Res|        │   └────<TAG=callee:x>
 | Res|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -33,4 +33,4 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Dis|        │ └─┬──<TAG=caller:x>
 | Dis|        │   └────<TAG=callee:x>
 | Act|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/formatting.stderr b/src/tools/miri/tests/pass/tree_borrows/formatting.stderr
index effd0d9f961..673dae6210d 100644
--- a/src/tools/miri/tests/pass/tree_borrows/formatting.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/formatting.stderr
@@ -1,4 +1,4 @@
-───────────────────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1..  2.. 10.. 11..100..101..1000..1001..1024
 | Act| Act| Act| Act| Act| Act|  Act|  Act|  Act|    └─┬──<TAG=root of the allocation>
@@ -7,8 +7,8 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 |----|----|----| Act|----|?Dis| ----| ?Dis| ----|        ├────<TAG=data[10]>
 |----|----|----|----|----| Frz| ----| ?Dis| ----|        ├────<TAG=data[100]>
 |----|----|----|----|----|----| ----|  Act| ----|        └────<TAG=data[1000]>
-───────────────────────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -28,4 +28,4 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Frz|          └─┬──<TAG=xcb>
 | Frz|            ├────<TAG=xcba>
 | Frz|            └────<TAG=xcbb>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr
index 8c4323b2f7f..b23d78a7156 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr
@@ -1,15 +1,15 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=parent>
 | Act|        └────<TAG=x>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=parent>
 | Frz|        ├────<TAG=x>
 | Res|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.stderr b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
index afb91700222..691fe8b7744 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
@@ -1,5 +1,5 @@
 [interior mut + protected] Foreign Read: Re* -> Frz
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -8,27 +8,27 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Re*|        │ └─┬──<TAG=caller:x>
 | Frz|        │   └────<TAG=callee:x>
 | Re*|        └────<TAG=y, caller:y, callee:y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 [interior mut] Foreign Read: Re* -> Re*
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  8
 | Act|    └─┬──<TAG=root of the allocation>
 | Re*|      └─┬──<TAG=base>
 | Re*|        ├────<TAG=x>
 | Re*|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 [interior mut] Foreign Write: Re* -> Re*
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  8
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Re*|        ├────<TAG=x>
 | Act|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 [protected] Foreign Read: Res -> Frz
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
@@ -37,22 +37,22 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | Res|        │ └─┬──<TAG=caller:x>
 | Frz|        │   └────<TAG=callee:x>
 | Res|        └────<TAG=y, caller:y, callee:y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 [] Foreign Read: Res -> Res
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Res|      └─┬──<TAG=base>
 | Res|        ├────<TAG=x>
 | Res|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 [] Foreign Write: Res -> Dis
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Dis|        ├────<TAG=x>
 | Act|        └────<TAG=y>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
index 6bdad695965..0d50d54faf6 100644
--- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
@@ -9,6 +9,7 @@ use std::ptr;
 fn main() {
     aliasing_read_only_mutable_refs();
     string_as_mut_ptr();
+    two_mut_protected_same_alloc();
 
     // Stacked Borrows tests
     read_does_not_invalidate1();
@@ -62,6 +63,23 @@ pub fn string_as_mut_ptr() {
     }
 }
 
+// This function checks that there is no issue with having two mutable references
+// from the same allocation both under a protector.
+// This is safe code, it must absolutely not be UB.
+// This test failing is a symptom of forgetting to check that only initialized
+// locations can cause protector UB.
+fn two_mut_protected_same_alloc() {
+    fn write_second(_x: &mut u8, y: &mut u8) {
+        // write through `y` will make some locations of `x` (protected)
+        // become Disabled. Those locations are outside of the range on which
+        // `x` is initialized, and the protector must not trigger.
+        *y = 1;
+    }
+
+    let mut data = (0u8, 1u8);
+    write_second(&mut data.0, &mut data.1);
+}
+
 // ----- The tests below were taken from Stacked Borrows ----
 
 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr
index 11e05d50f2c..f870d3bdec0 100644
--- a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr
@@ -1,21 +1,21 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Res|      └─┬──<TAG=base>
 | Res|        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Act|        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Act|        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr
index 5008b66741a..9ab6b879aa7 100644
--- a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr
@@ -1,24 +1,24 @@
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Res|      └─┬──<TAG=base>
 | Res|        └─┬──<TAG=raw>
 |----|          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Act|        └─┬──<TAG=raw>
 | Act|          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────────────────────────
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  1
 | Act|    └─┬──<TAG=root of the allocation>
 | Act|      └─┬──<TAG=base>
 | Act|        └─┬──<TAG=raw>
 | Dis|          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.default.stderr b/src/tools/miri/tests/pass/tree_borrows/vec_unique.default.stderr
index f1af1ea3d8b..a7712ae91fb 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.default.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.default.stderr
@@ -1,6 +1,6 @@
-─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  2
 | Act|    └─┬──<TAG=root of the allocation>
 | Res|      └────<TAG=base.as_ptr(), base.as_ptr(), raw_parts.0, reconstructed.as_ptr(), reconstructed.as_ptr()>
-─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
index 00ff1ee00eb..e9f1cb3b1ed 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
@@ -1,8 +1,8 @@
-──────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..  2
 | Act|    └─┬──<TAG=root of the allocation>
 |----|      └─┬──<TAG=base.as_ptr(), base.as_ptr()>
 |----|        └─┬──<TAG=raw_parts.0>
 |----|          └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
-──────────────────────────────────────────────────────────────────────────
+──────────────────────────────────────────────────
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 5a1794d3336..3f7dba81c3a 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -20,3 +20,4 @@ xz = "0.1"
 serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 glob = "0.3"
+tempfile = "3.5"
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
new file mode 100644
index 00000000000..e44b8a4db92
--- /dev/null
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -0,0 +1,98 @@
+use anyhow::Context;
+
+use crate::exec::cmd;
+use crate::training::LlvmBoltProfile;
+use camino::{Utf8Path, Utf8PathBuf};
+
+use crate::utils::io::copy_file;
+
+/// Instruments an artifact at the given `path` (in-place) with BOLT and then calls `func`.
+/// After this function finishes, the original file will be restored.
+pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>(
+    path: &Utf8Path,
+    func: F,
+) -> anyhow::Result<R> {
+    // Back up the original file.
+    // It will be restored to its original state when this function exits.
+    // By copying it, we break any existing hard links, so that they are not affected by the
+    // instrumentation.
+    let _backup_file = BackedUpFile::new(path)?;
+
+    let instrumented_path = tempfile::NamedTempFile::new()?.into_temp_path();
+
+    // Instrument the original file with BOLT, saving the result into `instrumented_path`
+    cmd(&["llvm-bolt"])
+        .arg("-instrument")
+        .arg(path)
+        // Make sure that each process will write its profiles into a separate file
+        .arg("--instrumentation-file-append-pid")
+        .arg("-o")
+        .arg(instrumented_path.display())
+        .run()
+        .with_context(|| anyhow::anyhow!("Could not instrument {path} using BOLT"))?;
+
+    // Copy the instrumented artifact over the original one
+    copy_file(&instrumented_path, path)?;
+
+    // Run the function that will make use of the instrumented artifact.
+    // The original file will be restored when `_backup_file` is dropped.
+    func()
+}
+
+/// Optimizes the file at `path` with BOLT in-place using the given `profile`.
+pub fn bolt_optimize(path: &Utf8Path, profile: &LlvmBoltProfile) -> anyhow::Result<()> {
+    // Copy the artifact to a new location, so that we do not use the same input and output file.
+    // BOLT cannot handle optimizing when the input and output is the same file, because it performs
+    // in-place patching.
+    let temp_path = tempfile::NamedTempFile::new()?.into_temp_path();
+    copy_file(path, &temp_path)?;
+
+    cmd(&["llvm-bolt"])
+        .arg(temp_path.display())
+        .arg("-data")
+        .arg(&profile.0)
+        .arg("-o")
+        .arg(path)
+        // Reorder basic blocks within functions
+        .arg("-reorder-blocks=ext-tsp")
+        // Reorder functions within the binary
+        .arg("-reorder-functions=hfsort+")
+        // Split function code into hot and code regions
+        .arg("-split-functions")
+        // Split as many basic blocks as possible
+        .arg("-split-all-cold")
+        // Move jump tables to a separate section
+        .arg("-jump-tables=move")
+        // Fold functions with identical code
+        .arg("-icf=1")
+        // Try to reuse old text segments to reduce binary size
+        .arg("--use-old-text")
+        // Update DWARF debug info in the final binary
+        .arg("-update-debug-sections")
+        // Print optimization statistics
+        .arg("-dyno-stats")
+        .run()
+        .with_context(|| anyhow::anyhow!("Could not optimize {path} with BOLT"))?;
+
+    Ok(())
+}
+
+/// Copies a file to a temporary location and restores it (copies it back) when it is dropped.
+pub struct BackedUpFile {
+    original: Utf8PathBuf,
+    backup: tempfile::TempPath,
+}
+
+impl BackedUpFile {
+    pub fn new(file: &Utf8Path) -> anyhow::Result<Self> {
+        let temp_path = tempfile::NamedTempFile::new()?.into_temp_path();
+        copy_file(file, &temp_path)?;
+        Ok(Self { backup: temp_path, original: file.to_path_buf() })
+    }
+}
+
+impl Drop for BackedUpFile {
+    fn drop(&mut self) {
+        copy_file(&self.backup, &self.original).expect("Cannot restore backed up file");
+    }
+}
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 3777c7c9718..4765dceb5dd 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -16,7 +16,7 @@ pub struct CmdBuilder {
 }
 
 impl CmdBuilder {
-    pub fn arg(mut self, arg: &str) -> Self {
+    pub fn arg<S: ToString>(mut self, arg: S) -> Self {
         self.args.push(arg.to_string());
         self
     }
@@ -154,13 +154,13 @@ impl Bootstrap {
         self
     }
 
-    pub fn llvm_bolt_instrument(mut self) -> Self {
-        self.cmd = self.cmd.arg("--llvm-bolt-profile-generate");
+    pub fn with_llvm_bolt_ldflags(mut self) -> Self {
+        self.cmd = self.cmd.arg("--set").arg("llvm.ldflags=-Wl,-q");
         self
     }
 
-    pub fn llvm_bolt_optimize(mut self, profile: &LlvmBoltProfile) -> Self {
-        self.cmd = self.cmd.arg("--llvm-bolt-profile-use").arg(profile.0.as_str());
+    pub fn with_bolt_profile(mut self, profile: LlvmBoltProfile) -> Self {
+        self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str());
         self
     }
 
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 08f5d61000d..f6edd008845 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -1,5 +1,7 @@
+use crate::bolt::{bolt_optimize, with_bolt_instrumented};
 use anyhow::Context;
 use log::LevelFilter;
+use utils::io;
 
 use crate::environment::{create_environment, Environment};
 use crate::exec::Bootstrap;
@@ -12,6 +14,7 @@ use crate::utils::{
     with_log_group,
 };
 
+mod bolt;
 mod environment;
 mod exec;
 mod metrics;
@@ -99,19 +102,35 @@ fn execute_pipeline(
         // BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc,
         // therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused.
         timer.section("Stage 3 (LLVM BOLT)", |stage| {
-            stage.section("Build BOLT instrumented LLVM", |stage| {
+            stage.section("Build PGO optimized LLVM", |stage| {
                 Bootstrap::build(env)
-                    .llvm_bolt_instrument()
+                    .with_llvm_bolt_ldflags()
                     .llvm_pgo_optimize(&llvm_pgo_profile)
                     .avoid_rustc_rebuild()
                     .run(stage)
             })?;
 
-            let profile = stage.section("Gather profiles", |_| gather_llvm_bolt_profiles(env))?;
+            // Find the path to the `libLLVM.so` file
+            let llvm_lib = io::find_file_in_dir(
+                &env.build_artifacts().join("stage2").join("lib"),
+                "libLLVM",
+                ".so",
+            )?;
+
+            // Instrument it and gather profiles
+            let profile = with_bolt_instrumented(&llvm_lib, || {
+                stage.section("Gather profiles", |_| gather_llvm_bolt_profiles(env))
+            })?;
             print_free_disk_space()?;
 
-            // LLVM is not being cleared here, we want to reuse the previous PGO-optimized build
+            // Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked
+            // from several places, and this specific path (`llvm_lib`) will *not* be packaged into
+            // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
+            // therefore it will actually optimize all the hard links, which means that the final
+            // packaged `libLLVM.so` file *will* be BOLT optimized.
+            bolt_optimize(&llvm_lib, &profile).context("Could not optimize LLVM with BOLT")?;
 
+            // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
             Ok(Some(profile))
         })?
     } else {
@@ -124,7 +143,7 @@ fn execute_pipeline(
         .avoid_rustc_rebuild();
 
     if let Some(llvm_bolt_profile) = llvm_bolt_profile {
-        dist = dist.llvm_bolt_optimize(&llvm_bolt_profile);
+        dist = dist.with_bolt_profile(llvm_bolt_profile);
     }
 
     // Final stage: Assemble the dist artifacts
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 6b35b13e586..c85418baecd 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -1,8 +1,8 @@
 use crate::environment::Environment;
 use crate::exec::cmd;
-use crate::utils::io::{copy_directory, unpack_archive};
+use crate::utils::io::{copy_directory, find_file_in_dir, unpack_archive};
 use anyhow::Context;
-use camino::Utf8PathBuf;
+use camino::{Utf8Path, Utf8PathBuf};
 
 /// Run tests on optimized dist artifacts.
 pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
@@ -22,13 +22,14 @@ pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
         Ok(extracted_path)
     };
     let host_triple = env.host_triple();
+    let version = find_dist_version(&dist_dir)?;
 
     // Extract rustc, libstd, cargo and src archives to create the optimized sysroot
-    let rustc_dir = extract_dist_dir(&format!("rustc-nightly-{host_triple}"))?.join("rustc");
-    let libstd_dir = extract_dist_dir(&format!("rust-std-nightly-{host_triple}"))?
+    let rustc_dir = extract_dist_dir(&format!("rustc-{version}-{host_triple}"))?.join("rustc");
+    let libstd_dir = extract_dist_dir(&format!("rust-std-{version}-{host_triple}"))?
         .join(format!("rust-std-{host_triple}"));
-    let cargo_dir = extract_dist_dir(&format!("cargo-nightly-{host_triple}"))?.join("cargo");
-    let extracted_src_dir = extract_dist_dir("rust-src-nightly")?.join("rust-src");
+    let cargo_dir = extract_dist_dir(&format!("cargo-{version}-{host_triple}"))?.join("cargo");
+    let extracted_src_dir = extract_dist_dir(&format!("rust-src-{version}"))?.join("rust-src");
 
     // We need to manually copy libstd to the extracted rustc sysroot
     copy_directory(
@@ -99,3 +100,15 @@ llvm-config = "{llvm_config}"
     }
     cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests")
 }
+
+/// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z).
+fn find_dist_version(directory: &Utf8Path) -> anyhow::Result<String> {
+    // Lookup a known file with a unique prefix and extract the version from its filename
+    let archive = find_file_in_dir(directory, "reproducible-artifacts-", ".tar.xz")?
+        .file_name()
+        .unwrap()
+        .to_string();
+    let (version, _) =
+        archive.strip_prefix("reproducible-artifacts-").unwrap().split_once("-").unwrap();
+    Ok(version.to_string())
+}
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 951bc6f9264..a9e88bdbb60 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -175,7 +175,7 @@ pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result<LlvmBo
             .context("Cannot gather LLVM BOLT profiles")
     })?;
 
-    let merged_profile = env.opt_artifacts().join("bolt.profdata");
+    let merged_profile = env.opt_artifacts().join("llvm-bolt.profdata");
     let profile_root = Utf8PathBuf::from("/tmp/prof.fdata");
     log::info!("Merging LLVM BOLT profiles to {merged_profile}");
 
diff --git a/src/tools/opt-dist/src/utils/io.rs b/src/tools/opt-dist/src/utils/io.rs
index aab078067af..8bd516fa349 100644
--- a/src/tools/opt-dist/src/utils/io.rs
+++ b/src/tools/opt-dist/src/utils/io.rs
@@ -2,6 +2,7 @@ use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 use fs_extra::dir::CopyOptions;
 use std::fs::File;
+use std::path::Path;
 
 /// Delete and re-create the directory.
 pub fn reset_directory(path: &Utf8Path) -> anyhow::Result<()> {
@@ -17,6 +18,12 @@ pub fn copy_directory(src: &Utf8Path, dst: &Utf8Path) -> anyhow::Result<()> {
     Ok(())
 }
 
+pub fn copy_file<S: AsRef<Path>, D: AsRef<Path>>(src: S, dst: D) -> anyhow::Result<()> {
+    log::info!("Copying file {} to {}", src.as_ref().display(), dst.as_ref().display());
+    std::fs::copy(src.as_ref(), dst.as_ref())?;
+    Ok(())
+}
+
 #[allow(unused)]
 pub fn move_directory(src: &Utf8Path, dst: &Utf8Path) -> anyhow::Result<()> {
     log::info!("Moving directory {src} to {dst}");
@@ -60,3 +67,22 @@ pub fn get_files_from_dir(
         .map(|p| p.map(|p| Utf8PathBuf::from_path_buf(p).unwrap()))
         .collect::<Result<Vec<_>, _>>()?)
 }
+
+/// Finds a single file in the specified `directory` with the given `prefix` and `suffix`.
+pub fn find_file_in_dir(
+    directory: &Utf8Path,
+    prefix: &str,
+    suffix: &str,
+) -> anyhow::Result<Utf8PathBuf> {
+    let files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))?
+        .into_iter()
+        .collect::<Result<Vec<_>, _>>()?;
+    match files.len() {
+        0 => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")),
+        1 => Ok(Utf8PathBuf::from_path_buf(files[0].clone()).unwrap()),
+        _ => Err(anyhow::anyhow!(
+            "More than one file with prefix {prefix} found in {directory}: {:?}",
+            files
+        )),
+    }
+}
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 57cbfe68be4..a015c36d7eb 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -270,18 +270,14 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "twox-hash",
     "type-map",
     "typenum",
-    "unic-char-property",
-    "unic-char-range",
-    "unic-common",
-    "unic-emoji-char",
     "unic-langid",
     "unic-langid-impl",
     "unic-langid-macros",
     "unic-langid-macros-impl",
-    "unic-ucd-version",
     "unicase",
     "unicode-ident",
     "unicode-normalization",
+    "unicode-properties",
     "unicode-script",
     "unicode-security",
     "unicode-width",
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 6cc7fbcacaf..44c7c07d3a0 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 const ISSUES_ENTRY_LIMIT: usize = 1893;
-const ROOT_ENTRY_LIMIT: usize = 872;
+const ROOT_ENTRY_LIMIT: usize = 873;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
@@ -100,7 +100,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             {
                 tidy_error!(bad, "file {} has unexpected extension {}", file_path.display(), ext);
             }
-            if ext == "stderr" || ext == "stdout" {
+            if ext == "stderr" || ext == "stdout" || ext == "fixed" {
                 // Test output filenames have one of the formats:
                 // ```
                 // $testname.stderr
diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs
index 148d11ee4d6..d152d200adf 100644
--- a/tests/assembly/is_aligned.rs
+++ b/tests/assembly/is_aligned.rs
@@ -1,5 +1,4 @@
 // assembly-output: emit-asm
-// min-llvm-version: 15.0
 // only-x86_64
 // ignore-sgx
 // revisions: opt-speed opt-size
diff --git a/tests/assembly/slice-is_ascii.rs b/tests/assembly/slice-is_ascii.rs
index b3e1fee15a7..12412116467 100644
--- a/tests/assembly/slice-is_ascii.rs
+++ b/tests/assembly/slice-is_ascii.rs
@@ -3,7 +3,6 @@
 // [LIN] only-linux
 // assembly-output: emit-asm
 // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
-// min-llvm-version: 14
 // only-x86_64
 // ignore-sgx
 // ignore-debug
diff --git a/tests/assembly/strict_provenance.rs b/tests/assembly/strict_provenance.rs
index 24a7c6b5bf1..ef8566a93e2 100644
--- a/tests/assembly/strict_provenance.rs
+++ b/tests/assembly/strict_provenance.rs
@@ -2,7 +2,6 @@
 // compile-flags: -Copt-level=1
 // only-x86_64
 // ignore-sgx
-// min-llvm-version: 15.0
 #![crate_type = "rlib"]
 
 // CHECK-LABEL: old_style
diff --git a/tests/codegen/abi-main-signature-16bit-c-int.rs b/tests/codegen/abi-main-signature-16bit-c-int.rs
index 353e7489b55..ce4d35dea0c 100644
--- a/tests/codegen/abi-main-signature-16bit-c-int.rs
+++ b/tests/codegen/abi-main-signature-16bit-c-int.rs
@@ -2,22 +2,10 @@
 // entry point. It must match C's `int main(int, char **)`.
 
 // This test is for targets with 16bit c_int only.
-// ignore-aarch64
-// ignore-arm
-// ignore-asmjs
-// ignore-hexagon
-// ignore-mips
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-riscv64
-// ignore-s390x
-// ignore-sparc
-// ignore-sparc64
-// ignore-wasm32
-// ignore-x86
-// ignore-x86_64
-// ignore-loongarch64
+// revisions: avr msp
+//[avr] only-avr
+//[msp] only-msp430
+
 
 fn main() {
 }
diff --git a/tests/codegen/abi-main-signature-32bit-c-int.rs b/tests/codegen/abi-main-signature-32bit-c-int.rs
index 7f22ddcfc12..34571823f13 100644
--- a/tests/codegen/abi-main-signature-32bit-c-int.rs
+++ b/tests/codegen/abi-main-signature-32bit-c-int.rs
@@ -3,8 +3,9 @@
 
 // This test is for targets with 32bit c_int only.
 // ignore-msp430
+// ignore-avr
 
 fn main() {
 }
 
-// CHECK: define{{( hidden)?}} i32 @main(i32{{( %0)?}}, {{i8\*\*|ptr}}{{( %1)?}})
+// CHECK: define{{( hidden)?}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}})
diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs
index 6dfc1825015..97af6181524 100644
--- a/tests/codegen/addr-of-mutate.rs
+++ b/tests/codegen/addr-of-mutate.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C opt-level=3 -C no-prepopulate-passes
-// min-llvm-version: 15.0 (for opaque pointers)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs
index b53a68a5588..0739c79ba8d 100644
--- a/tests/codegen/adjustments.rs
+++ b/tests/codegen/adjustments.rs
@@ -13,9 +13,9 @@ pub fn helper(_: usize) {
 pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] {
     // We used to generate an extra alloca and memcpy for the block's trailing expression value, so
     // check that we copy directly to the return value slot
-// CHECK: %0 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } poison, {{\[0 x i8\]\*|ptr}} %x.0, 0
-// CHECK: %1 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %0, [[USIZE]] %x.1, 1
-// CHECK: ret { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %1
+// CHECK: %0 = insertvalue { ptr, [[USIZE]] } poison, ptr %x.0, 0
+// CHECK: %1 = insertvalue { ptr, [[USIZE]] } %0, [[USIZE]] %x.1, 1
+// CHECK: ret { ptr, [[USIZE]] } %1
     { x }
 }
 
diff --git a/tests/codegen/align-enum.rs b/tests/codegen/align-enum.rs
index 70f09ace006..5901f0113c3 100644
--- a/tests/codegen/align-enum.rs
+++ b/tests/codegen/align-enum.rs
@@ -20,7 +20,7 @@ pub struct Nested64 {
 #[no_mangle]
 pub fn align64(a: u32) -> Align64 {
 // CHECK: %a64 = alloca %Align64, align 64
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 64 %{{.*}}, {{i8\*|ptr}} align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
     let a64 = Align64::A(a);
     a64
 }
diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs
index 7c7660c5a55..d4d8b18d35b 100644
--- a/tests/codegen/align-offset.rs
+++ b/tests/codegen/align-offset.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 15.0 (because we're using opaque pointers)
 // ignore-debug (debug assertions in `slice::from_raw_parts` block optimizations)
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs
index a2f47354b2b..40bba6d5254 100644
--- a/tests/codegen/align-struct.rs
+++ b/tests/codegen/align-struct.rs
@@ -32,7 +32,7 @@ pub enum Enum64 {
 #[no_mangle]
 pub fn align64(i : i32) -> Align64 {
 // CHECK: %a64 = alloca %Align64, align 64
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 64 %{{.*}}, {{i8\*|ptr}} align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
     let a64 = Align64(i);
     a64
 }
@@ -42,7 +42,7 @@ pub fn align64(i : i32) -> Align64 {
 // CHECK-LABEL: @align64_load
 #[no_mangle]
 pub fn align64_load(a: Align64) -> i32 {
-// CHECK: {{%.*}} = load i32, {{i32\*|ptr}} {{%.*}}, align 64
+// CHECK: {{%.*}} = load i32, ptr {{%.*}}, align 64
     a.0
 }
 
diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs
index 71acd781549..ba0d444f97e 100644
--- a/tests/codegen/array-codegen.rs
+++ b/tests/codegen/array-codegen.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O -C no-prepopulate-passes
-// min-llvm-version: 15.0 (for opaque pointers)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs
index abfe295f8b6..1941452ea61 100644
--- a/tests/codegen/array-equality.rs
+++ b/tests/codegen/array-equality.rs
@@ -16,8 +16,8 @@ pub fn array_eq_value(a: [u16; 3], b: [u16; 3]) -> bool {
 #[no_mangle]
 pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool {
     // CHECK: start:
-    // CHECK: load i48, {{i48\*|ptr}} %{{.+}}, align 2
-    // CHECK: load i48, {{i48\*|ptr}} %{{.+}}, align 2
+    // CHECK: load i48, ptr %{{.+}}, align 2
+    // CHECK: load i48, ptr %{{.+}}, align 2
     // CHECK: icmp eq i48
     // CHECK-NEXT: ret
     a == b
@@ -27,7 +27,7 @@ pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool {
 #[no_mangle]
 pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool {
     // CHECK-NEXT: start:
-    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{i8\*|ptr}} {{.*}} dereferenceable(18) %{{.+}}, {{i8\*|ptr}} {{.*}} dereferenceable(18) %{{.+}}, i64 18)
+    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18) %{{.+}}, i64 18)
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     a == b
@@ -37,7 +37,7 @@ pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool
 #[no_mangle]
 pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool {
     // CHECK-NEXT: start:
-    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{i8\*|ptr}} {{.*}} dereferenceable(2468) %{{.+}}, {{i8\*|ptr}} {{.*}} dereferenceable(2468) %{{.+}}, i64 2468)
+    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(2468) %{{.+}}, ptr {{.*}} dereferenceable(2468) %{{.+}}, i64 2468)
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     a == b
diff --git a/tests/codegen/atomic-operations.rs b/tests/codegen/atomic-operations.rs
index d2bc618dfc5..20980c48960 100644
--- a/tests/codegen/atomic-operations.rs
+++ b/tests/codegen/atomic-operations.rs
@@ -7,37 +7,37 @@ use std::sync::atomic::{AtomicI32, Ordering::*};
 // CHECK-LABEL: @compare_exchange
 #[no_mangle]
 pub fn compare_exchange(a: &AtomicI32) {
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 10 monotonic monotonic
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 11 monotonic acquire
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 12 monotonic seq_cst
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 10 monotonic monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 11 monotonic acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 12 monotonic seq_cst
     let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
     let _ = a.compare_exchange(0, 11, Relaxed, Acquire);
     let _ = a.compare_exchange(0, 12, Relaxed, SeqCst);
 
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 20 release monotonic
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 21 release acquire
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 22 release seq_cst
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 20 release monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 21 release acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 22 release seq_cst
     let _ = a.compare_exchange(0, 20, Release, Relaxed);
     let _ = a.compare_exchange(0, 21, Release, Acquire);
     let _ = a.compare_exchange(0, 22, Release, SeqCst);
 
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 30 acquire monotonic
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 31 acquire acquire
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 32 acquire seq_cst
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 30 acquire monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 31 acquire acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 32 acquire seq_cst
     let _ = a.compare_exchange(0, 30, Acquire, Relaxed);
     let _ = a.compare_exchange(0, 31, Acquire, Acquire);
     let _ = a.compare_exchange(0, 32, Acquire, SeqCst);
 
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 40 acq_rel monotonic
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 41 acq_rel acquire
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 42 acq_rel seq_cst
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 41 acq_rel acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 42 acq_rel seq_cst
     let _ = a.compare_exchange(0, 40, AcqRel, Relaxed);
     let _ = a.compare_exchange(0, 41, AcqRel, Acquire);
     let _ = a.compare_exchange(0, 42, AcqRel, SeqCst);
 
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 50 seq_cst monotonic
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 51 seq_cst acquire
-    // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 52 seq_cst seq_cst
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 51 seq_cst acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 52 seq_cst seq_cst
     let _ = a.compare_exchange(0, 50, SeqCst, Relaxed);
     let _ = a.compare_exchange(0, 51, SeqCst, Acquire);
     let _ = a.compare_exchange(0, 52, SeqCst, SeqCst);
@@ -46,37 +46,37 @@ pub fn compare_exchange(a: &AtomicI32) {
 // CHECK-LABEL: @compare_exchange_weak
 #[no_mangle]
 pub fn compare_exchange_weak(w: &AtomicI32) {
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 10 monotonic monotonic
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 11 monotonic acquire
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 12 monotonic seq_cst
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 10 monotonic monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 11 monotonic acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 12 monotonic seq_cst
     let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed);
     let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire);
     let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst);
 
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 20 release monotonic
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 21 release acquire
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 22 release seq_cst
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 20 release monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 21 release acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 22 release seq_cst
     let _ = w.compare_exchange_weak(1, 20, Release, Relaxed);
     let _ = w.compare_exchange_weak(1, 21, Release, Acquire);
     let _ = w.compare_exchange_weak(1, 22, Release, SeqCst);
 
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 30 acquire monotonic
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 31 acquire acquire
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 32 acquire seq_cst
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 30 acquire monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 31 acquire acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 32 acquire seq_cst
     let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed);
     let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire);
     let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst);
 
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 40 acq_rel monotonic
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 41 acq_rel acquire
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 42 acq_rel seq_cst
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 41 acq_rel acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 42 acq_rel seq_cst
     let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed);
     let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire);
     let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst);
 
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 50 seq_cst monotonic
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 51 seq_cst acquire
-    // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 52 seq_cst seq_cst
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 51 seq_cst acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 52 seq_cst seq_cst
     let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed);
     let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire);
     let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst);
diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
index 83baae9e432..dc36a9fac8c 100644
--- a/tests/codegen/avr/avr-func-addrspace.rs
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -94,7 +94,7 @@ pub extern "C" fn test() {
 
 // Validate that we can codegen transmutes between data ptrs and fn ptrs.
 
-// CHECK: define{{.+}}{{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @transmute_data_ptr_to_fn({{\{\}\*|ptr}}{{.*}} %x)
+// CHECK: define{{.+}}ptr addrspace(1) @transmute_data_ptr_to_fn(ptr{{.*}} %x)
 #[no_mangle]
 pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
     // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
@@ -102,7 +102,7 @@ pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
     transmute(x)
 }
 
-// CHECK: define{{.+}}{{\{\}\*|ptr}} @transmute_fn_ptr_to_data({{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}}{{.*}} %x)
+// CHECK: define{{.+}}ptr @transmute_fn_ptr_to_data(ptr addrspace(1){{.*}} %x)
 #[no_mangle]
 pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
     // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
@@ -116,7 +116,7 @@ pub enum Either<T, U> { A(T), B(U) }
 // with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
 // This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
 
-// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%_0, {{.+\*|ptr}}{{.+}}%x)
+// CHECK: define{{.+}}void @should_not_combine_addrspace(ptr{{.+}}sret{{.+}}%_0, ptr{{.+}}%x)
 #[no_mangle]
 #[inline(never)]
 pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs
index 5c08b5832ad..282af99b067 100644
--- a/tests/codegen/box-maybe-uninit.rs
+++ b/tests/codegen/box-maybe-uninit.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 15.0
 #![crate_type = "lib"]
 
 use std::mem::MaybeUninit;
diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs
index a9d25e3b53c..7a2a3fc93f8 100644
--- a/tests/codegen/comparison-operators-2-tuple.rs
+++ b/tests/codegen/comparison-operators-2-tuple.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C opt-level=1 -Z merge-functions=disabled
-// min-llvm-version: 15.0
 // only-x86_64
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs
index 683a2bd4fbb..8fd8a81dfeb 100644
--- a/tests/codegen/comparison-operators-newtype.rs
+++ b/tests/codegen/comparison-operators-newtype.rs
@@ -3,7 +3,6 @@
 // in the operators for such a type all optimize away.
 
 // compile-flags: -C opt-level=1
-// min-llvm-version: 15.0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs
index 810da581ce9..3797e1a99da 100644
--- a/tests/codegen/consts.rs
+++ b/tests/codegen/consts.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C no-prepopulate-passes
-// min-llvm-version: 15.0 (for opaque pointers)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/drop-in-place-noalias.rs b/tests/codegen/drop-in-place-noalias.rs
index 725e6fc048d..ece1e426c08 100644
--- a/tests/codegen/drop-in-place-noalias.rs
+++ b/tests/codegen/drop-in-place-noalias.rs
@@ -7,9 +7,9 @@
 
 use std::marker::PhantomPinned;
 
-// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}({{.*\*|ptr}} noalias noundef align 4 dereferenceable(12) %{{.+}})
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}})
 
-// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}({{.*\*|ptr}} noundef nonnull align 4 %{{.+}})
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}})
 
 pub struct StructUnpin {
     a: i32,
diff --git a/tests/codegen/fastcall-inreg.rs b/tests/codegen/fastcall-inreg.rs
index 02f5d545910..ab19efa45bf 100644
--- a/tests/codegen/fastcall-inreg.rs
+++ b/tests/codegen/fastcall-inreg.rs
@@ -19,7 +19,7 @@ pub mod tests {
     #[no_mangle]
     pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
 
-    // CHECK: @f2({{i32\*|ptr}} inreg noundef %_1, {{i32\*|ptr}} inreg noundef %_2, {{i32\*|ptr}} noundef %_3)
+    // CHECK: @f2(ptr inreg noundef %_1, ptr inreg noundef %_2, ptr noundef %_3)
     #[no_mangle]
     pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
 
diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs
index f99cc8fb415..8fe6c790dda 100644
--- a/tests/codegen/function-arguments-noopt.rs
+++ b/tests/codegen/function-arguments-noopt.rs
@@ -23,13 +23,13 @@ pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool {
   f(x)
 }
 
-// CHECK: align 4 {{i32\*|ptr}} @borrow({{i32\*|ptr}} align 4 %x)
+// CHECK: align 4 ptr @borrow(ptr align 4 %x)
 #[no_mangle]
 pub fn borrow(x: &i32) -> &i32 {
   x
 }
 
-// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x)
+// CHECK: align 4 ptr @borrow_mut(ptr align 4 %x)
 #[no_mangle]
 pub fn borrow_mut(x: &mut i32) -> &mut i32 {
   x
@@ -38,11 +38,11 @@ pub fn borrow_mut(x: &mut i32) -> &mut i32 {
 // CHECK-LABEL: @borrow_call
 #[no_mangle]
 pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
-  // CHECK: call align 4 {{i32\*|ptr}} %f({{i32\*|ptr}} align 4 %x)
+  // CHECK: call align 4 ptr %f(ptr align 4 %x)
   f(x)
 }
 
-// CHECK: void @struct_({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %x)
+// CHECK: void @struct_(ptr sret(%S) align 4{{( %_0)?}}, ptr align 4 %x)
 #[no_mangle]
 pub fn struct_(x: S) -> S {
   x
@@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S {
 // CHECK-LABEL: @struct_call
 #[no_mangle]
 pub fn struct_call(x: S, f: fn(S) -> S) -> S {
-  // CHECK: call void %f({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %{{.+}})
+  // CHECK: call void %f(ptr sret(%S) align 4{{( %_0)?}}, ptr align 4 %{{.+}})
   f(x)
 }
 
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 2f047f10311..a218596da1d 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -80,95 +80,95 @@ pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
   x
 }
 
-// CHECK: @readonly_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {
 }
 
-// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
+// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret()
 #[no_mangle]
 pub fn readonly_borrow_ret() -> &'static i32 {
   loop {}
 }
 
-// CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
 pub fn static_borrow(_: &'static i32) {
 }
 
-// CHECK: @named_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
 // borrow with named lifetime may be captured
 #[no_mangle]
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef nonnull align 2 %_1)
+// CHECK: @unsafe_borrow(ptr noundef nonnull align 2 %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow({{i16\*|ptr}} noalias noundef align 2 dereferenceable(2) %_1)
+// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1)
 // ... unless this is a mutable borrow, those never alias
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow({{i32\*|ptr}} noalias noundef align 4 dereferenceable(4) %_1)
+// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
 
-// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
+// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret()
 #[no_mangle]
 pub fn mutable_borrow_ret() -> &'static mut i32 {
   loop {}
 }
 
 #[no_mangle]
-// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
+// CHECK: @mutable_notunpin_borrow(ptr noundef nonnull align 4 %_1)
 // This one is *not* `noalias` because it might be self-referential.
 // It is also not `dereferenceable` due to
 // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
 pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
 }
 
-// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
 // But `&NotUnpin` behaves perfectly normal.
 #[no_mangle]
 pub fn notunpin_borrow(_: &NotUnpin) {
 }
 
-// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly align 4 dereferenceable(32) %_1)
+// CHECK: @indirect_struct(ptr noalias nocapture noundef readonly align 4 dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
 
-// CHECK: @borrowed_struct({{%S\*|ptr}} noalias noundef readonly align 4 dereferenceable(32) %_1)
+// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {
 }
 
-// CHECK: @option_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
+// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
 #[no_mangle]
 pub fn option_borrow(x: Option<&i32>) {
 }
 
-// CHECK: @option_borrow_mut({{i32\*|ptr}} noalias noundef align 4 dereferenceable_or_null(4) %x)
+// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %x)
 #[no_mangle]
 pub fn option_borrow_mut(x: Option<&mut i32>) {
 }
 
-// CHECK: @raw_struct({{%S\*|ptr}} noundef %_1)
+// CHECK: @raw_struct(ptr noundef %_1)
 #[no_mangle]
 pub fn raw_struct(_: *const S) {
 }
 
-// CHECK: @raw_option_nonnull_struct({{i32\*|ptr}} noundef %_1)
+// CHECK: @raw_option_nonnull_struct(ptr noundef %_1)
 #[no_mangle]
 pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {
 }
@@ -176,19 +176,19 @@ pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {
 
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
-// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 ptr @_box(ptr noalias noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> Box<i32> {
   x
 }
 
-// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @notunpin_box({{i32\*|ptr}} noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
   x
 }
 
-// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) align 4 dereferenceable(32){{( %_0)?}})
+// CHECK: @struct_return(ptr noalias nocapture noundef sret(%S) align 4 dereferenceable(32){{( %_0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
   S {
@@ -202,68 +202,68 @@ pub fn struct_return() -> S {
 pub fn helper(_: usize) {
 }
 
-// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
 
-// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_slice(_: &[UnsafeInner]) {
 }
 
-// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} noundef %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @raw_slice(ptr noundef %_1.0, [[USIZE]] noundef %_1.1)
 #[no_mangle]
 pub fn raw_slice(_: *const [u8]) {
 }
 
-// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow({{\{\}\*|ptr}} noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn trait_borrow(_: &dyn Drop) {
 }
 
-// CHECK: @option_trait_borrow({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1)
 #[no_mangle]
 pub fn option_trait_borrow(x: Option<&dyn Drop>) {
 }
 
-// CHECK: @option_trait_borrow_mut({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1)
 #[no_mangle]
 pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {
 }
 
-// CHECK: @trait_raw({{\{\}\*|ptr}} noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 #[no_mangle]
 pub fn trait_raw(_: *const dyn Drop) {
 }
 
-// CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
+// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
 #[no_mangle]
 pub fn trait_box(_: Box<dyn Drop + Unpin>) {
 }
 
-// CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1)
 #[no_mangle]
 pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
   x
 }
 
-// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
+// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
 #[no_mangle]
 pub fn return_slice(x: &[u16]) -> &[u16] {
   x
@@ -281,7 +281,7 @@ pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
   x
 }
 
-// CHECK: { {{\{\}\*|ptr}}, {{.+}} } @dyn_star({{\{\}\*|ptr}} noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1)
+// CHECK: { ptr, {{.+}} } @dyn_star(ptr noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1)
 // Expect an ABI something like `{ {}*, [3 x i64]* }`, but that's hard to match on generically,
 // so do like the `trait_box` test and just match on `{{.+}}` for the vtable.
 #[no_mangle]
diff --git a/tests/codegen/global_asm.rs b/tests/codegen/global_asm.rs
index 41a99530ad2..4c2ccf4e0e9 100644
--- a/tests/codegen/global_asm.rs
+++ b/tests/codegen/global_asm.rs
@@ -1,24 +1,6 @@
-// ignore-aarch64
-// ignore-arm
-// ignore-avr
-// ignore-bpf
-// ignore-bpf
-// ignore-hexagon
-// ignore-mips
-// ignore-mips64
-// ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc
-// ignore-sparc
-// ignore-sparc64
-// ignore-s390x
-// ignore-thumb
-// ignore-nvptx64
-// ignore-spirv
-// ignore-wasm32
-// ignore-wasm64
-// ignore-emscripten
-// ignore-loongarch64
+// revisions: x32 x64
+//[x32] only-x86
+//[x64] only-x86_64
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/global_asm_include.rs b/tests/codegen/global_asm_include.rs
index e25c164f407..0fede8c71e4 100644
--- a/tests/codegen/global_asm_include.rs
+++ b/tests/codegen/global_asm_include.rs
@@ -1,24 +1,6 @@
-// ignore-aarch64
-// ignore-arm
-// ignore-avr
-// ignore-bpf
-// ignore-bpf
-// ignore-hexagon
-// ignore-mips
-// ignore-mips64
-// ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc
-// ignore-sparc
-// ignore-sparc64
-// ignore-s390x
-// ignore-thumb
-// ignore-nvptx64
-// ignore-spirv
-// ignore-wasm32
-// ignore-wasm64
-// ignore-emscripten
-// ignore-loongarch64
+// revisions: x32 x64
+//[x32] only-x86
+//[x64] only-x86_64
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/global_asm_x2.rs b/tests/codegen/global_asm_x2.rs
index 71ecef124f1..1fc2825b2bd 100644
--- a/tests/codegen/global_asm_x2.rs
+++ b/tests/codegen/global_asm_x2.rs
@@ -1,24 +1,6 @@
-// ignore-aarch64
-// ignore-arm
-// ignore-avr
-// ignore-bpf
-// ignore-bpf
-// ignore-hexagon
-// ignore-mips
-// ignore-mips64
-// ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc
-// ignore-sparc
-// ignore-sparc64
-// ignore-s390x
-// ignore-thumb
-// ignore-nvptx64
-// ignore-spirv
-// ignore-wasm32
-// ignore-wasm64
-// ignore-emscripten
-// ignore-loongarch64
+// revisions: x32 x64
+//[x32] only-x86
+//[x64] only-x86_64
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/intrinsics/mask.rs b/tests/codegen/intrinsics/mask.rs
index 8f93da2e5da..82131c55847 100644
--- a/tests/codegen/intrinsics/mask.rs
+++ b/tests/codegen/intrinsics/mask.rs
@@ -7,6 +7,6 @@
 #[no_mangle]
 pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 {
     // CHECK: call
-    // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%1}}, [[WORD]] %mask)
+    // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]](ptr {{%ptr|%1}}, [[WORD]] %mask)
     core::intrinsics::ptr_mask(ptr, mask)
 }
diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs
index d8ee2945266..dc020c12119 100644
--- a/tests/codegen/intrinsics/nontemporal.rs
+++ b/tests/codegen/intrinsics/nontemporal.rs
@@ -6,7 +6,7 @@
 #[no_mangle]
 pub fn a(a: &mut u32, b: u32) {
     // CHECK-LABEL: define{{.*}}void @a
-    // CHECK: store i32 %b, {{i32\*|ptr}} %a, align 4, !nontemporal
+    // CHECK: store i32 %b, ptr %a, align 4, !nontemporal
     unsafe {
         std::intrinsics::nontemporal_store(a, b);
     }
diff --git a/tests/codegen/intrinsics/offset.rs b/tests/codegen/intrinsics/offset.rs
index 7fc4f4498d6..542bacf99a8 100644
--- a/tests/codegen/intrinsics/offset.rs
+++ b/tests/codegen/intrinsics/offset.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O -C no-prepopulate-passes
-// min-llvm-version: 15.0 (because we're using opaque pointers)
 
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs
index fffc24a1181..e9c8d803cb9 100644
--- a/tests/codegen/intrinsics/transmute-niched.rs
+++ b/tests/codegen/intrinsics/transmute-niched.rs
@@ -2,7 +2,6 @@
 // [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes
 // [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes
 // only-64bit (so I don't need to worry about usize)
-// min-llvm-version: 15.0 # this test assumes `ptr`s
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs
index 168838ef497..19020f6280a 100644
--- a/tests/codegen/intrinsics/transmute-x64.rs
+++ b/tests/codegen/intrinsics/transmute-x64.rs
@@ -1,6 +1,5 @@
 // compile-flags: -O -C no-prepopulate-passes
 // only-x86_64 (it's using arch-specific types)
-// min-llvm-version: 15.0 # this test assumes `ptr`s
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
index f8c20960660..e64af33ab6c 100644
--- a/tests/codegen/intrinsics/transmute.rs
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -1,6 +1,5 @@
 // compile-flags: -O -C no-prepopulate-passes
 // only-64bit (so I don't need to worry about usize)
-// min-llvm-version: 15.0 # this test assumes `ptr`s
 
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
diff --git a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
index 6e0eacfe400..f345c96e6f7 100644
--- a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
+++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
@@ -1,6 +1,5 @@
 // compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes -Zmir-enable-passes=-ScalarReplacementOfAggregates
 // MIR SROA will decompose the closure
-// min-llvm-version: 15.0 # this test uses opaque pointer notation
 #![feature(stmt_expr_attributes)]
 
 pub struct S([usize; 8]);
@@ -16,8 +15,8 @@ pub fn outer_function(x: S, y: S) -> usize {
 // Check that we do not attempt to load from the spilled arg before it is assigned to
 // when generating debuginfo.
 // CHECK-LABEL: @outer_function
-// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:10:23: 10:25]"
-// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:10:23: 10:25]", ptr [[spill]]
+// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]"
+// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
 // CHECK-NOT: [[load:%.*]] = load ptr, ptr
 // CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
 // CHECK: [[inner:%.*]] = getelementptr inbounds %"{{.*}}", ptr [[spill]]
diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs
index 4f386d335c7..329769940f9 100644
--- a/tests/codegen/issues/issue-37945.rs
+++ b/tests/codegen/issues/issue-37945.rs
@@ -12,11 +12,11 @@ use std::slice::Iter;
 pub fn is_empty_1(xs: Iter<f32>) -> bool {
 // CHECK-LABEL: @is_empty_1(
 // CHECK-NEXT:  start:
-// CHECK-NEXT:    [[A:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null
+// CHECK-NEXT:    [[A:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[A]])
 // The order between %xs.0 and %xs.1 on the next line doesn't matter
 // and different LLVM versions produce different order.
-// CHECK-NEXT:    [[B:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}}
+// CHECK-NEXT:    [[B:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}}
 // CHECK-NEXT:    ret i1 [[B:%.*]]
     {xs}.next().is_none()
 }
@@ -25,11 +25,11 @@ pub fn is_empty_1(xs: Iter<f32>) -> bool {
 pub fn is_empty_2(xs: Iter<f32>) -> bool {
 // CHECK-LABEL: @is_empty_2
 // CHECK-NEXT:  start:
-// CHECK-NEXT:    [[C:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null
+// CHECK-NEXT:    [[C:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[C]])
 // The order between %xs.0 and %xs.1 on the next line doesn't matter
 // and different LLVM versions produce different order.
-// CHECK-NEXT:    [[D:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}}
+// CHECK-NEXT:    [[D:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}}
 // CHECK-NEXT:    ret i1 [[D:%.*]]
     xs.map(|&x| x).next().is_none()
 }
diff --git a/tests/codegen/issues/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs
index 4dc9ebfebbc..1715e9f05ab 100644
--- a/tests/codegen/issues/issue-56267-2.rs
+++ b/tests/codegen/issues/issue-56267-2.rs
@@ -11,7 +11,7 @@ pub struct Foo<T> {
 // The load from bar.1 should have alignment 4. Not checking
 // other loads here, as the alignment will be platform-dependent.
 
-// CHECK: %{{.+}} = load i32, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: %{{.+}} = load i32, ptr %{{.+}}, align 4
 #[no_mangle]
 pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) {
     x.bar
diff --git a/tests/codegen/issues/issue-56267.rs b/tests/codegen/issues/issue-56267.rs
index 7bdd2577998..90aa9f7ae89 100644
--- a/tests/codegen/issues/issue-56267.rs
+++ b/tests/codegen/issues/issue-56267.rs
@@ -11,7 +11,7 @@ pub struct Foo<T> {
 // The store writing to bar.1 should have alignment 4. Not checking
 // other stores here, as the alignment will be platform-dependent.
 
-// CHECK: store i32 [[TMP1:%.+]], {{i32\*|ptr}} [[TMP2:%.+]], align 4
+// CHECK: store i32 [[TMP1:%.+]], ptr [[TMP2:%.+]], align 4
 #[no_mangle]
 pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> {
     Foo { foo: 0, bar: x }
diff --git a/tests/codegen/issues/issue-56927.rs b/tests/codegen/issues/issue-56927.rs
index 044d721814b..1b09ce565b3 100644
--- a/tests/codegen/issues/issue-56927.rs
+++ b/tests/codegen/issues/issue-56927.rs
@@ -8,10 +8,10 @@ pub struct S {
 }
 
 // CHECK-LABEL: @test1
-// CHECK: store i32 0, {{i32\*|ptr}} %{{.+}}, align 16
-// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 4
-// CHECK: store i32 2, {{i32\*|ptr}} %{{.+}}, align 8
-// CHECK: store i32 3, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: store i32 0, ptr %{{.+}}, align 16
+// CHECK: store i32 1, ptr %{{.+}}, align 4
+// CHECK: store i32 2, ptr %{{.+}}, align 8
+// CHECK: store i32 3, ptr %{{.+}}, align 4
 #[no_mangle]
 pub fn test1(s: &mut S) {
     s.arr[0] = 0;
@@ -21,7 +21,7 @@ pub fn test1(s: &mut S) {
 }
 
 // CHECK-LABEL: @test2
-// CHECK: store i32 4, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: store i32 4, ptr %{{.+}}, align 4
 #[allow(unconditional_panic)]
 #[no_mangle]
 pub fn test2(s: &mut S) {
@@ -29,14 +29,14 @@ pub fn test2(s: &mut S) {
 }
 
 // CHECK-LABEL: @test3
-// CHECK: store i32 5, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: store i32 5, ptr %{{.+}}, align 4
 #[no_mangle]
 pub fn test3(s: &mut S, i: usize) {
     s.arr[i] = 5;
 }
 
 // CHECK-LABEL: @test4
-// CHECK: store i32 6, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: store i32 6, ptr %{{.+}}, align 4
 #[no_mangle]
 pub fn test4(s: &mut S) {
     s.arr = [6; 4];
diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs
index 00f8953d949..a1d0e8eb7e0 100644
--- a/tests/codegen/issues/issue-58881.rs
+++ b/tests/codegen/issues/issue-58881.rs
@@ -16,6 +16,6 @@ struct Bar(u64, u64, u64);
 
 // Ensure that emit arguments of the correct type.
 pub unsafe fn test_call_variadic() {
-    // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}})
+    // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, ptr {{.*}})
     variadic_fn(0, Foo(0), Bar(0, 0, 0))
 }
diff --git a/tests/codegen/issues/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs
index 591a1aca747..a4723a0e946 100644
--- a/tests/codegen/issues/issue-85872-multiple-reverse.rs
+++ b/tests/codegen/issues/issue-85872-multiple-reverse.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 15.0.0
 // compile-flags: -O
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs
index be5034dcfbd..15aef344ac0 100644
--- a/tests/codegen/issues/issue-86106.rs
+++ b/tests/codegen/issues/issue-86106.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 15.0
 // only-64bit llvm appears to use stores instead of memset on 32bit
 // compile-flags: -C opt-level=3 -Z merge-functions=disabled
 
diff --git a/tests/codegen/issues/issue-96274.rs b/tests/codegen/issues/issue-96274.rs
index 28bfcce0d7b..a44789ce350 100644
--- a/tests/codegen/issues/issue-96274.rs
+++ b/tests/codegen/issues/issue-96274.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 15.0
 // compile-flags: -O
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/issues/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs
index 0413ed6b26f..3ea6a5405e5 100644
--- a/tests/codegen/issues/issue-96497-slice-size-nowrap.rs
+++ b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs
@@ -3,7 +3,6 @@
 // in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218
 
 // compile-flags: -O
-// min-llvm-version: 15.0
 
 #![crate_type="lib"]
 
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 7da29cd7952..b87e43c13b6 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 @@
-// min-llvm-version: 15.0.0
 // ignore-debug: The debug assertions get in the way
 // compile-flags: -O
 
diff --git a/tests/codegen/lifetime_start_end.rs b/tests/codegen/lifetime_start_end.rs
index 471a0b8cedd..16175dc18c2 100644
--- a/tests/codegen/lifetime_start_end.rs
+++ b/tests/codegen/lifetime_start_end.rs
@@ -8,7 +8,7 @@ pub fn test() {
     let a = 0u8;
     &a; // keep variable in an alloca
 
-// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %a)
+// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %a)
 
     {
         let b = &Some(a);
@@ -26,9 +26,9 @@ pub fn test() {
     let c = 1u8;
     &c; // keep variable in an alloca
 
-// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %c)
+// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %c)
 
-// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %c)
+// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %c)
 
-// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %a)
+// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %a)
 }
diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs
index f29a26596bf..4a09a1dc033 100644
--- a/tests/codegen/loads.rs
+++ b/tests/codegen/loads.rs
@@ -28,22 +28,22 @@ pub fn ptr_alignment_helper(x: &&()) {}
 // CHECK-LABEL: @load_ref
 #[no_mangle]
 pub fn load_ref<'a>(x: &&'a i32) -> &'a i32 {
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_ref_higher_alignment
 #[no_mangle]
 pub fn load_ref_higher_alignment<'a>(x: &&'a Align16) -> &'a Align16 {
-    // CHECK: load {{%Align16\*|i128\*|ptr}}, {{%Align16\*\*|i128\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_scalar_pair
 #[no_mangle]
 pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16) {
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
-    // CHECK: load {{i64\*|ptr}}, {{i64\*\*|ptr}} %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}}
     *x
 }
 
@@ -51,70 +51,70 @@ pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16
 #[no_mangle]
 pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
     // loaded raw pointer should not have !nonnull or !align metadata
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}}
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}}
     *x
 }
 
 // CHECK-LABEL: @load_box
 #[no_mangle]
 pub fn load_box<'a>(x: Box<Box<i32>>) -> Box<i32> {
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_bool
 #[no_mangle]
 pub fn load_bool(x: &bool) -> bool {
-    // CHECK: load i8, {{i8\*|ptr}} %x, align 1, !range ![[BOOL_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
+    // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_maybeuninit_bool
 #[no_mangle]
 pub fn load_maybeuninit_bool(x: &MaybeUninit<bool>) -> MaybeUninit<bool> {
-    // CHECK: load i8, {{i8\*|ptr}} %x, align 1{{$}}
+    // CHECK: load i8, ptr %x, align 1{{$}}
     *x
 }
 
 // CHECK-LABEL: @load_enum_bool
 #[no_mangle]
 pub fn load_enum_bool(x: &MyBool) -> MyBool {
-    // CHECK: load i8, {{i8\*|ptr}} %x, align 1, !range ![[BOOL_RANGE]], !noundef !{{[0-9]+}}
+    // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_maybeuninit_enum_bool
 #[no_mangle]
 pub fn load_maybeuninit_enum_bool(x: &MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
-    // CHECK: load i8, {{i8\*|ptr}} %x, align 1{{$}}
+    // CHECK: load i8, ptr %x, align 1{{$}}
     *x
 }
 
 // CHECK-LABEL: @load_int
 #[no_mangle]
 pub fn load_int(x: &u16) -> u16 {
-    // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+    // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}}
     *x
 }
 
 // CHECK-LABEL: @load_nonzero_int
 #[no_mangle]
 pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 {
-    // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
+    // CHECK: load i16, ptr %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
     *x
 }
 
 // CHECK-LABEL: @load_option_nonzero_int
 #[no_mangle]
 pub fn load_option_nonzero_int(x: &Option<NonZeroU16>) -> Option<NonZeroU16> {
-    // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+    // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}}
     *x
 }
 
 // CHECK-LABEL: @borrow
 #[no_mangle]
 pub fn borrow(x: &i32) -> &i32 {
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x{{.*}}, !nonnull
+    // CHECK: load ptr, ptr %x{{.*}}, !nonnull
     &x; // keep variable in an alloca
     x
 }
@@ -122,7 +122,7 @@ pub fn borrow(x: &i32) -> &i32 {
 // CHECK-LABEL: @_box
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> i32 {
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x{{.*}}, align [[PTR_ALIGNMENT]]
+    // CHECK: load ptr, ptr %x{{.*}}, align [[PTR_ALIGNMENT]]
     *x
 }
 
@@ -131,7 +131,7 @@ pub fn _box(x: Box<i32>) -> i32 {
 // dependent alignment
 #[no_mangle]
 pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] {
-    // CHECK: [[VAR:%[0-9]+]] = load i32, {{i32\*|ptr}} %{{.*}}, align 1
+    // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1
     // CHECK: ret i32 [[VAR]]
     x
 }
@@ -141,7 +141,7 @@ pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] {
 // dependent alignment
 #[no_mangle]
 pub fn small_struct_alignment(x: Bytes) -> Bytes {
-    // CHECK: [[VAR:%[0-9]+]] = load i32, {{i32\*|ptr}} %{{.*}}, align 1
+    // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1
     // CHECK: ret i32 [[VAR]]
     x
 }
diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs
index 59e6eeb7c5d..e32a5e54504 100644
--- a/tests/codegen/match-optimized.rs
+++ b/tests/codegen/match-optimized.rs
@@ -20,13 +20,13 @@ pub fn exhaustive_match(e: E) -> u8 {
 // CHECK-NEXT: unreachable
 //
 // CHECK: [[A]]:
-// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %_0, align 1
+// CHECK-NEXT: store i8 0, ptr %_0, align 1
 // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
 // CHECK: [[B]]:
-// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %_0, align 1
+// CHECK-NEXT: store i8 1, ptr %_0, align 1
 // CHECK-NEXT: br label %[[EXIT]]
 // CHECK: [[C]]:
-// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %_0, align 1
+// CHECK-NEXT: store i8 2, ptr %_0, align 1
 // CHECK-NEXT: br label %[[EXIT]]
     match e {
         E::A => 0,
diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs
index 55c2741faaf..fc3e9d22bdf 100644
--- a/tests/codegen/mem-replace-big-type.rs
+++ b/tests/codegen/mem-replace-big-type.rs
@@ -25,9 +25,9 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big {
 // For a large type, we expect exactly three `memcpy`s
 // CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big)
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %result, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %result, ptr align 8 %dest, i{{.*}} 56, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %dest, {{i8\*|ptr}} align 8 %src, i{{.*}} 56, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %dest, ptr align 8 %src, i{{.*}} 56, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
 
 // CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs
index 5c4acf813ea..174ac608e01 100644
--- a/tests/codegen/mem-replace-simple-type.rs
+++ b/tests/codegen/mem-replace-simple-type.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O -C no-prepopulate-passes
-// min-llvm-version: 15.0 (for opaque pointers)
 // only-x86_64 (to not worry about usize differing)
 // ignore-debug (the debug assertions get in the way)
 
diff --git a/tests/codegen/move-operands.rs b/tests/codegen/move-operands.rs
index df4fbe29ffd..cd87e6d813c 100644
--- a/tests/codegen/move-operands.rs
+++ b/tests/codegen/move-operands.rs
@@ -7,7 +7,7 @@ type T = [u8; 256];
 
 #[no_mangle]
 pub fn f(a: T, b: fn(_: T, _: T)) {
-    // CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, {{.*}} 256, i1 false)
-    // CHECK-NOT: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, {{.*}} 256, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false)
     b(a, a)
 }
diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs
index a394695f3bd..ce5b6328af6 100644
--- a/tests/codegen/option-nonzero-eq.rs
+++ b/tests/codegen/option-nonzero-eq.rs
@@ -32,7 +32,7 @@ pub fn non_zero_signed_eq(l: Option<NonZeroI64>, r: Option<NonZeroI64>) -> bool
 #[no_mangle]
 pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
     // CHECK: start:
-    // CHECK-NEXT: icmp eq {{(i8\*|ptr)}}
+    // CHECK-NEXT: icmp eq ptr
     // CHECK-NEXT: ret i1
     l == r
 }
diff --git a/tests/codegen/packed.rs b/tests/codegen/packed.rs
index fd63b4f0acd..96cd9a42e7d 100644
--- a/tests/codegen/packed.rs
+++ b/tests/codegen/packed.rs
@@ -18,8 +18,8 @@ pub struct Packed2 {
 // CHECK-LABEL: @write_pkd1
 #[no_mangle]
 pub fn write_pkd1(pkd: &mut Packed1) -> u32 {
-// CHECK: %{{.*}} = load i32, {{i32\*|ptr}} %{{.*}}, align 1
-// CHECK: store i32 42, {{i32\*|ptr}} %{{.*}}, align 1
+// CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 1
+// CHECK: store i32 42, ptr %{{.*}}, align 1
     let result = pkd.data;
     pkd.data = 42;
     result
@@ -28,8 +28,8 @@ pub fn write_pkd1(pkd: &mut Packed1) -> u32 {
 // CHECK-LABEL: @write_pkd2
 #[no_mangle]
 pub fn write_pkd2(pkd: &mut Packed2) -> u32 {
-// CHECK: %{{.*}} = load i32, {{i32\*|ptr}} %{{.*}}, align 2
-// CHECK: store i32 42, {{i32\*|ptr}} %{{.*}}, align 2
+// CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 2
+// CHECK: store i32 42, ptr %{{.*}}, align 2
     let result = pkd.data;
     pkd.data = 42;
     result
@@ -52,8 +52,8 @@ pub struct BigPacked2 {
 #[no_mangle]
 pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
 // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
-// CHECK: call void %{{.*}}({{%Array\*|ptr}} noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+// CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
     // unaligned destination.
@@ -64,8 +64,8 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
 #[no_mangle]
 pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
 // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
-// CHECK: call void %{{.*}}({{%Array\*|ptr}} noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|ptr}} align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+// CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
     // unaligned destination.
@@ -73,9 +73,9 @@ pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
 }
 
 // CHECK-LABEL: @write_packed_array1
-// CHECK: store i32 0, {{i32\*|ptr}} %{{.+}}, align 1
-// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 1
-// CHECK: store i32 2, {{i32\*|ptr}} %{{.+}}, align 1
+// CHECK: store i32 0, ptr %{{.+}}, align 1
+// CHECK: store i32 1, ptr %{{.+}}, align 1
+// CHECK: store i32 2, ptr %{{.+}}, align 1
 #[no_mangle]
 pub fn write_packed_array1(p: &mut BigPacked1) {
     p.data.0[0] = 0;
@@ -84,9 +84,9 @@ pub fn write_packed_array1(p: &mut BigPacked1) {
 }
 
 // CHECK-LABEL: @write_packed_array2
-// CHECK: store i32 0, {{i32\*|ptr}} %{{.+}}, align 2
-// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 2
-// CHECK: store i32 2, {{i32\*|ptr}} %{{.+}}, align 2
+// CHECK: store i32 0, ptr %{{.+}}, align 2
+// CHECK: store i32 1, ptr %{{.+}}, align 2
+// CHECK: store i32 2, ptr %{{.+}}, align 2
 #[no_mangle]
 pub fn write_packed_array2(p: &mut BigPacked2) {
     p.data.0[0] = 0;
@@ -95,14 +95,14 @@ pub fn write_packed_array2(p: &mut BigPacked2) {
 }
 
 // CHECK-LABEL: @repeat_packed_array1
-// CHECK: store i32 42, {{i32\*|ptr}} %{{.+}}, align 1
+// CHECK: store i32 42, ptr %{{.+}}, align 1
 #[no_mangle]
 pub fn repeat_packed_array1(p: &mut BigPacked1) {
     p.data.0 = [42; 8];
 }
 
 // CHECK-LABEL: @repeat_packed_array2
-// CHECK: store i32 42, {{i32\*|ptr}} %{{.+}}, align 2
+// CHECK: store i32 42, ptr %{{.+}}, align 2
 #[no_mangle]
 pub fn repeat_packed_array2(p: &mut BigPacked2) {
     p.data.0 = [42; 8];
@@ -119,14 +119,14 @@ pub struct Packed2Pair(u8, u32);
 // CHECK-LABEL: @pkd1_pair
 #[no_mangle]
 pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) {
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false)
     *pair2 = *pair1;
 }
 
 // CHECK-LABEL: @pkd2_pair
 #[no_mangle]
 pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) {
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|ptr}} align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false)
     *pair2 = *pair1;
 }
 
@@ -141,13 +141,13 @@ pub struct Packed2NestedPair((u32, u32));
 // CHECK-LABEL: @pkd1_nested_pair
 #[no_mangle]
 pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) {
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false)
     *pair2 = *pair1;
 }
 
 // CHECK-LABEL: @pkd2_nested_pair
 #[no_mangle]
 pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) {
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|ptr}} align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false)
     *pair2 = *pair1;
 }
diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs
index 9ff7a9b3e88..47243bece98 100644
--- a/tests/codegen/personality_lifetimes.rs
+++ b/tests/codegen/personality_lifetimes.rs
@@ -22,7 +22,7 @@ pub fn test() {
     let _s = S;
     // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
     // in the first one.
-    // CHECK: [[SLOT:%[0-9]+]] = alloca { {{i8\*|ptr}}, i32 }
+    // CHECK: [[SLOT:%[0-9]+]] = alloca { ptr, i32 }
     // CHECK-LABEL: cleanup:
     // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}})
     // CHECK-LABEL: cleanup1:
diff --git a/tests/codegen/refs.rs b/tests/codegen/refs.rs
index a5289766711..1c7746a3079 100644
--- a/tests/codegen/refs.rs
+++ b/tests/codegen/refs.rs
@@ -13,9 +13,9 @@ pub fn helper(_: usize) {
 pub fn ref_dst(s: &[u8]) {
     // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
     // directly to the alloca for "x"
-// CHECK: [[X0:%[0-9]+]] = getelementptr inbounds { {{\[0 x i8\]\*|ptr}}, [[USIZE]] }, {{.*}}  %x, i32 0, i32 0
-// CHECK: store {{\[0 x i8\]\*|ptr}} %s.0, {{.*}} [[X0]]
-// CHECK: [[X1:%[0-9]+]] = getelementptr inbounds { {{\[0 x i8\]\*|ptr}}, [[USIZE]] }, {{.*}} %x, i32 0, i32 1
+// CHECK: [[X0:%[0-9]+]] = getelementptr inbounds { ptr, [[USIZE]] }, {{.*}}  %x, i32 0, i32 0
+// CHECK: store ptr %s.0, {{.*}} [[X0]]
+// CHECK: [[X1:%[0-9]+]] = getelementptr inbounds { ptr, [[USIZE]] }, {{.*}} %x, i32 0, i32 1
 // CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]]
 
     let x = &*s;
diff --git a/tests/codegen/repeat-trusted-len.rs b/tests/codegen/repeat-trusted-len.rs
index d06978f2435..bd6ff977e1f 100644
--- a/tests/codegen/repeat-trusted-len.rs
+++ b/tests/codegen/repeat-trusted-len.rs
@@ -8,13 +8,13 @@ use std::iter;
 // CHECK-LABEL: @repeat_take_collect
 #[no_mangle]
 pub fn repeat_take_collect() -> Vec<u8> {
-    // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false)
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false)
     iter::repeat(42).take(100000).collect()
 }
 
 // CHECK-LABEL: @repeat_with_take_collect
 #[no_mangle]
 pub fn repeat_with_take_collect() -> Vec<u8> {
-    // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false)
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false)
     iter::repeat_with(|| 13).take(12345).collect()
 }
diff --git a/tests/codegen/repr-transparent-aggregates-1.rs b/tests/codegen/repr-transparent-aggregates-1.rs
deleted file mode 100644
index ba3ba272efb..00000000000
--- a/tests/codegen/repr-transparent-aggregates-1.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-// compile-flags: -O -C no-prepopulate-passes
-//
-
-// ignore-arm
-// ignore-aarch64
-// ignore-mips
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-riscv64 see codegen/riscv-abi
-// ignore-s390x
-// ignore-windows
-// ignore-loongarch64
-// ignore-wasm32-bare
-// See repr-transparent.rs
-
-#![feature(transparent_unions)]
-
-#![crate_type="lib"]
-
-
-#[derive(Clone, Copy)]
-#[repr(C)]
-pub struct BigS([u32; 16]);
-
-#[repr(transparent)]
-pub struct TsBigS(BigS);
-
-#[repr(transparent)]
-pub union TuBigS {
-    field: BigS,
-}
-
-#[repr(transparent)]
-pub enum TeBigS {
-    Variant(BigS),
-}
-
-// CHECK: define{{.*}}void @test_BigS({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], {{%BigS\*|ptr}} [[BIGS_ARG_ATTRS1:.*]] byval(%BigS) [[BIGS_ARG_ATTRS2:.*]])
-#[no_mangle]
-pub extern "C" fn test_BigS(_: BigS) -> BigS { loop {} }
-
-// CHECK: define{{.*}}void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], {{%TsBigS\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%TsBigS) [[BIGS_ARG_ATTRS2:.*]])
-#[no_mangle]
-pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
-
-// CHECK: define{{.*}}void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], {{%TuBigS\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%TuBigS) [[BIGS_ARG_ATTRS2:.*]])
-#[no_mangle]
-pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
-
-// CHECK: define{{.*}}void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], {{%"TeBigS::Variant"\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%"TeBigS::Variant") [[BIGS_ARG_ATTRS2]])
-#[no_mangle]
-pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
-
-
-#[derive(Clone, Copy)]
-#[repr(C)]
-pub union BigU {
-    foo: [u32; 16],
-}
-
-#[repr(transparent)]
-pub struct TsBigU(BigU);
-
-#[repr(transparent)]
-pub union TuBigU {
-    field: BigU,
-}
-
-#[repr(transparent)]
-pub enum TeBigU {
-    Variant(BigU),
-}
-
-// CHECK: define{{.*}}void @test_BigU({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], {{%BigU\*|ptr}} [[BIGU_ARG_ATTRS1:.*]] byval(%BigU) [[BIGU_ARG_ATTRS2:.*]])
-#[no_mangle]
-pub extern "C" fn test_BigU(_: BigU) -> BigU { loop {} }
-
-// CHECK: define{{.*}}void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%TsBigU) [[BIGU_RET_ATTRS2:.*]], {{%TsBigU\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%TsBigU) [[BIGU_ARG_ATTRS2]])
-#[no_mangle]
-pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
-
-// CHECK: define{{.*}}void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2:.*]], {{%TuBigU\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%TuBigU) [[BIGU_ARG_ATTRS2]])
-#[no_mangle]
-pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
-
-// CHECK: define{{.*}}void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2:.*]], {{%"TeBigU::Variant"\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%"TeBigU::Variant") [[BIGU_ARG_ATTRS2]])
-#[no_mangle]
-pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-aggregates-2.rs b/tests/codegen/repr-transparent-aggregates-2.rs
deleted file mode 100644
index a7bde2d05c3..00000000000
--- a/tests/codegen/repr-transparent-aggregates-2.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-//
-
-// ignore-aarch64
-// ignore-emscripten
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-riscv64 see codegen/riscv-abi
-// ignore-s390x
-// ignore-sparc
-// ignore-sparc64
-// ignore-x86
-// ignore-x86_64
-// ignore-loongarch64
-// See repr-transparent.rs
-
-#![feature(transparent_unions)]
-
-#![crate_type="lib"]
-
-
-#[derive(Clone, Copy)]
-#[repr(C)]
-pub struct BigS([u32; 16]);
-
-#[repr(transparent)]
-pub struct TsBigS(BigS);
-
-#[repr(transparent)]
-pub union TuBigS {
-    field: BigS,
-}
-
-#[repr(transparent)]
-pub enum TeBigS {
-    Variant(BigS),
-}
-
-// CHECK: define void @test_BigS({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
-#[no_mangle]
-pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
-
-// CHECK: define void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
-
-// CHECK: define void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
-
-// CHECK: define void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
-
-
-#[derive(Clone, Copy)]
-#[repr(C)]
-pub union BigU {
-    foo: [u32; 16],
-}
-
-#[repr(transparent)]
-pub struct TsBigU(BigU);
-
-#[repr(transparent)]
-pub union TuBigU {
-    field: BigU,
-}
-
-#[repr(transparent)]
-pub enum TeBigU {
-    Variant(BigU),
-}
-
-// CHECK: define void @test_BigU({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
-#[no_mangle]
-pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
-
-// CHECK: define void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
-
-// CHECK: define void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
-
-// CHECK: define void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32]
-#[no_mangle]
-pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr/transparent-imm-array.rs b/tests/codegen/repr/transparent-imm-array.rs
new file mode 100644
index 00000000000..6d712778509
--- /dev/null
+++ b/tests/codegen/repr/transparent-imm-array.rs
@@ -0,0 +1,86 @@
+// revisions: arm mips thumb wasm32
+// compile-flags: -C no-prepopulate-passes
+//
+//[arm] only-arm
+//[mips] only-mips
+//[thumb] only-thumb
+//[wasm32] only-wasm32
+// ignore-emscripten
+// See ./transparent.rs
+// Some platforms pass large aggregates using immediate arrays in LLVMIR
+// Other platforms pass large aggregates using struct pointer in LLVMIR
+// This covers the "immediate array" case.
+
+#![feature(transparent_unions)]
+
+#![crate_type="lib"]
+
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
+
+// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
+
+// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
+
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-aggregates-3.rs b/tests/codegen/repr/transparent-mips64.rs
index 0db17e6b13a..245daf13e28 100644
--- a/tests/codegen/repr-transparent-aggregates-3.rs
+++ b/tests/codegen/repr/transparent-mips64.rs
@@ -2,7 +2,7 @@
 //
 
 // only-mips64
-// See repr-transparent.rs
+// See ./transparent.rs
 
 #![feature(transparent_unions)]
 
diff --git a/tests/codegen/repr/transparent-struct-ptr.rs b/tests/codegen/repr/transparent-struct-ptr.rs
new file mode 100644
index 00000000000..d2120f7ec14
--- /dev/null
+++ b/tests/codegen/repr/transparent-struct-ptr.rs
@@ -0,0 +1,87 @@
+// revisions: x32 x64 sparc sparc64
+// compile-flags: -O -C no-prepopulate-passes
+//
+//[x32] only-x86
+//[x64] only-x86_64
+//[sparc] only-sparc
+//[sparc64] only-sparc64
+// ignore-windows
+// See ./transparent.rs
+// Some platforms pass large aggregates using immediate arrays in LLVMIR
+// Other platforms pass large aggregates using struct pointer in LLVMIR
+// This covers the "struct pointer" case.
+
+
+#![feature(transparent_unions)]
+
+#![crate_type="lib"]
+
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval(%BigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%TsBigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%TuBigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%"TeBigS::Variant") [[BIGS_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
+
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval(%BigU) [[BIGU_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%TsBigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%TsBigU) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%TuBigU) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%"TeBigU::Variant") [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-sysv64.rs b/tests/codegen/repr/transparent-sysv64.rs
index 886b0dd9e7b..886b0dd9e7b 100644
--- a/tests/codegen/repr-transparent-sysv64.rs
+++ b/tests/codegen/repr/transparent-sysv64.rs
diff --git a/tests/codegen/repr-transparent.rs b/tests/codegen/repr/transparent.rs
index 759ddea67a5..b140fc719da 100644
--- a/tests/codegen/repr-transparent.rs
+++ b/tests/codegen/repr/transparent.rs
@@ -1,10 +1,13 @@
 // compile-flags: -O -C no-prepopulate-passes
-
 // ignore-riscv64 riscv64 has an i128 type used with test_Vector
-// see codegen/riscv-abi for riscv functiona call tests
 // ignore-s390x s390x with default march passes vector types per reference
 // ignore-loongarch64 see codegen/loongarch-abi for loongarch function call tests
 
+// This codegen test embeds assumptions about how certain "C" psABIs are handled
+// so it doesn't apply to all architectures or even all OS
+// For RISCV: see codegen/riscv-abi
+// For LoongArch: see codegen/loongarch-abi
+
 #![crate_type="lib"]
 #![feature(repr_simd, transparent_unions)]
 
@@ -26,7 +29,7 @@ pub extern "C" fn test_F32(_: F32) -> F32 { loop {} }
 #[repr(transparent)]
 pub struct Ptr(*mut u8);
 
-// CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} noundef %_1)
+// CHECK: define{{.*}}ptr @test_Ptr(ptr noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { loop {} }
 
@@ -41,7 +44,7 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
 
 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
-// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} noundef %_1)
+// CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
 
@@ -65,7 +68,7 @@ pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { lo
 #[repr(transparent)]
 pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
 
-// CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} noundef %_1)
+// CHECK: define{{.*}}ptr @test_LifetimePhantom(ptr noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
 
@@ -159,7 +162,7 @@ pub union UnionF32WithZsts {
 pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
 
 
-// All that remains to be tested are aggregates. They are tested in separate files called repr-
+// All that remains to be tested are aggregates. They are tested in separate files called
 // transparent-*.rs  with `only-*` or `ignore-*` directives, because the expected LLVM IR
 // function signatures vary so much that it's not reasonably possible to cover all of them with a
 // single CHECK line.
diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
index ec18fa9a328..fdb9c6217de 100644
--- a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
+++ b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
@@ -127,18 +127,18 @@ pub struct Large {
     d: i64,
 }
 
-// CHECK: define void @f_agg_large({{%Large\*|ptr}} {{.*}}%x)
+// CHECK: define void @f_agg_large(ptr {{.*}}%x)
 #[no_mangle]
 pub extern "C" fn f_agg_large(mut x: Large) {
 }
 
-// CHECK: define void @f_agg_large_ret({{%Large\*|ptr}} {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j)
+// CHECK: define void @f_agg_large_ret(ptr {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j)
 #[no_mangle]
 pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large {
     Large { a: 1, b: 2, c: 3, d: 4 }
 }
 
-// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, {{%Large\*|ptr}} {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h)
+// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h)
 #[no_mangle]
 pub extern "C" fn f_scalar_stack_1(
     a: Tiny,
@@ -152,7 +152,7 @@ pub extern "C" fn f_scalar_stack_1(
 ) {
 }
 
-// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+// CHECK: define void @f_scalar_stack_2(ptr {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
 #[no_mangle]
 pub extern "C" fn f_scalar_stack_2(
     a: u64,
@@ -172,7 +172,7 @@ extern "C" {
 
 #[no_mangle]
 pub unsafe extern "C" fn f_va_caller() {
-    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, {{%Large\*|ptr}} {{.*}})
+    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, ptr {{.*}})
     f_va_callee(
         1,
         2i32,
diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer-cfi-emit-type-checks.rs
index cea6aac8b8b..f0fe5de9f66 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-checks.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-checks.rs
@@ -8,7 +8,7 @@
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
     // CHECK:       start:
-    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"{{[[:print:]]+}}")
+    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}")
     // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail
     // CHECK:       type_test.pass:
     // CHECK-NEXT:  {{%.+}} = call i32 %f(i32 %arg)
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
index 78ef0c2c7d6..d200ed9798a 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
@@ -8,21 +8,21 @@
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}foo
     // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized")
     f(arg)
 }
 
 pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}bar
     // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized")
     f(arg1, arg2)
 }
 
 pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}baz
     // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized")
     f(arg1, arg2, arg3)
 }
 
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
index 3b72459c4b0..cdefec17a1c 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
@@ -8,21 +8,21 @@
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}foo
     // CHECK-SAME:  {{.*}}![[TYPE1:[0-9]+]]
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized")
     f(arg)
 }
 
 pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}bar
     // CHECK-SAME:  {{.*}}![[TYPE2:[0-9]+]]
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized")
     f(arg1, arg2)
 }
 
 pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}baz
     // CHECK-SAME:  {{.*}}![[TYPE3:[0-9]+]]
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized")
     f(arg1, arg2, arg3)
 }
 
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
index 9218e9947bf..f360b33ddcf 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
@@ -8,21 +8,21 @@
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}foo
     // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized")
     f(arg)
 }
 
 pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}bar
     // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized")
     f(arg1, arg2)
 }
 
 pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}baz
     // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized")
     f(arg1, arg2, arg3)
 }
 
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
index f9fd816dedb..3cb817b212d 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
@@ -8,21 +8,21 @@
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}foo
     // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E")
     f(arg)
 }
 
 pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}bar
     // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E")
     f(arg1, arg2)
 }
 
 pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
     // CHECK-LABEL: define{{.*}}baz
     // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E")
     f(arg1, arg2, arg3)
 }
 
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs
index d24e416b67e..b69e57261a8 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs
@@ -68,7 +68,7 @@ impl<T, U, const N: usize> Trait5<U, N> for T {
 pub fn foo1(a: &dyn Trait1) {
     a.foo();
     // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]")
 }
 
 pub fn bar1() {
@@ -76,13 +76,13 @@ pub fn bar1() {
     let b = &a as &dyn Trait1;
     b.foo();
     // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
 }
 
 pub fn foo2<T>(a: &dyn Trait2<T>) {
     a.bar();
     // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
 }
 
 pub fn bar2() {
@@ -91,14 +91,14 @@ pub fn bar2() {
     let b = &a as &dyn Trait2<i32>;
     b.bar();
     // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
 }
 
 pub fn foo3(a: &dyn Trait3<Type3>) {
     let b = Type3;
     a.baz(&b);
     // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
 }
 
 pub fn bar3() {
@@ -107,14 +107,14 @@ pub fn bar3() {
     let b = &a as &dyn Trait3<Type3>;
     b.baz(&a);
     // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
 }
 
 pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) {
     let b = Type4;
     a.qux(&b);
     // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
 }
 
 pub fn bar4<'a>() {
@@ -123,14 +123,14 @@ pub fn bar4<'a>() {
     let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>;
     b.qux(&a);
     // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
 }
 
 pub fn foo5(a: &dyn Trait5<Type5, 32>) {
     let b = &[Type5; 32];
     a.quux(&b);
     // CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
 }
 
 pub fn bar5() {
@@ -139,7 +139,7 @@ pub fn bar5() {
     let b = &a as &dyn Trait5<Type5, 32>;
     b.quux(&a);
     // CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}}
-    // CHECK:       call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
 }
 
 // CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"}
diff --git a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs
index 78ecc187b8e..7aed137f215 100644
--- a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs
@@ -93,7 +93,7 @@ impl<T, U, const N: usize> Trait5<U, N> for T {
 pub fn foo1(a: &dyn Trait1) {
     a.foo();
     // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
 }
 
 pub fn bar1() {
@@ -101,13 +101,13 @@ pub fn bar1() {
     let b = &a as &dyn Trait1;
     b.foo();
     // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
 }
 
 pub fn foo2<T>(a: &dyn Trait2<T>) {
     a.bar();
     // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
 }
 
 pub fn bar2() {
@@ -116,14 +116,14 @@ pub fn bar2() {
     let b = &a as &dyn Trait2<i32>;
     b.bar();
     // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
 }
 
 pub fn foo3(a: &dyn Trait3<Type3>) {
     let b = Type3;
     a.baz(&b);
     // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
 }
 
 pub fn bar3() {
@@ -132,14 +132,14 @@ pub fn bar3() {
     let b = &a as &dyn Trait3<Type3>;
     b.baz(&a);
     // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
 }
 
 pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) {
     let b = Type4;
     a.qux(&b);
     // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call align 4 {{ptr|i32\*}} %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type4\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
+    // CHECK:       call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
 }
 
 pub fn bar4<'a>() {
@@ -148,14 +148,14 @@ pub fn bar4<'a>() {
     let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>;
     b.qux(&a);
     // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call align 4 {{ptr|i32\*}} %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type4\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
+    // CHECK:       call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
 }
 
 pub fn foo5(a: &dyn Trait5<Type5, 32>) {
     let b = &[Type5; 32];
     a.quux(&b);
     // CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, {{\{\}\*|ptr|\[32 x %Type5\]\*}} align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
 }
 
 pub fn bar5() {
@@ -164,7 +164,7 @@ pub fn bar5() {
     let b = &a as &dyn Trait5<Type5, 32>;
     b.quux(&a);
     // CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
-    // CHECK:       call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, {{\{\}\*|ptr|\[32 x %Type5\]\*}} align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
 }
 
 // CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
index cacc32f2f1b..0bb21019685 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -23,7 +23,7 @@ extern "platform-intrinsic" {
 #[no_mangle]
 pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
                            values: Vec2<f32>) -> Vec2<f32> {
-    // CHECK: call <2 x float> @llvm.masked.gather.v2f32.{{.+}}(<2 x {{float\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x float> {{.*}})
+    // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x float> {{.*}})
     simd_gather(values, pointers, mask)
 }
 
@@ -31,6 +31,6 @@ pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn gather_pf32x2(pointers: Vec2<*const *const f32>, mask: Vec2<i32>,
                            values: Vec2<*const f32>) -> Vec2<*const f32> {
-    // CHECK: call <2 x {{float\*|ptr}}> @llvm.masked.gather.{{.+}}(<2 x {{float\*\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x {{float\*|ptr}}> {{.*}})
+    // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x ptr> {{.*}})
     simd_gather(values, pointers, mask)
 }
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
index 94ecaf6096d..51953560b4f 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -23,7 +23,7 @@ extern "platform-intrinsic" {
 #[no_mangle]
 pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
                             values: Vec2<f32>) {
-    // CHECK: call void @llvm.masked.scatter.v2f32.v2p0{{.*}}(<2 x float> {{.*}}, <2 x {{float\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
+    // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
     simd_scatter(values, pointers, mask)
 }
 
@@ -32,6 +32,6 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn scatter_pf32x2(pointers: Vec2<*mut *const f32>, mask: Vec2<i32>,
                              values: Vec2<*const f32>) {
-    // CHECK: call void @llvm.masked.scatter.v2p0{{.*}}.v2p0{{.*}}(<2 x {{float\*|ptr}}> {{.*}}, <2 x {{float\*\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
+    // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
     simd_scatter(values, pointers, mask)
 }
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
index 3a0e37de2f3..eb4ce307e70 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -42,8 +42,8 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> {
 // CHECK-LABEL: @build_array_transmute_s
 #[no_mangle]
 pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
-    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
-    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
 
@@ -57,8 +57,8 @@ pub fn build_array_t(x: [f32; 4]) -> T {
 // CHECK-LABEL: @build_array_transmute_t
 #[no_mangle]
 pub fn build_array_transmute_t(x: [f32; 4]) -> T {
-    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
-    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
 
@@ -76,7 +76,7 @@ pub fn build_array_u(x: [f32; 4]) -> U {
 // CHECK-LABEL: @build_array_transmute_u
 #[no_mangle]
 pub fn build_array_transmute_u(x: [f32; 4]) -> U {
-    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
-    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
diff --git a/tests/codegen/simd_arith_offset.rs b/tests/codegen/simd_arith_offset.rs
index 74d7edc70d7..1ee73de1186 100644
--- a/tests/codegen/simd_arith_offset.rs
+++ b/tests/codegen/simd_arith_offset.rs
@@ -21,6 +21,6 @@ pub struct Simd<T, const LANES: usize>([T; LANES]);
 // CHECK-LABEL: smoke
 #[no_mangle]
 pub fn smoke(ptrs: SimdConstPtr<u8, 8>, offsets: Simd<usize, 8>) -> SimdConstPtr<u8, 8> {
-    // CHECK: getelementptr i8, <8 x {{i8\*|ptr}}> %0, <8 x i64> %1
+    // CHECK: getelementptr i8, <8 x ptr> %0, <8 x i64> %1
     unsafe { simd_arith_offset(ptrs, offsets) }
 }
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index d80628cb1d4..c0bf1a04119 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -23,7 +23,7 @@ pub fn zero_len_array() {
 // CHECK-LABEL: @byte_array
 #[no_mangle]
 pub fn byte_array() {
-    // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 7, i{{[0-9]+}} 4
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 7, i{{[0-9]+}} 4
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [7u8; 4];
     opaque(&x);
@@ -39,7 +39,7 @@ enum Init {
 // CHECK-LABEL: @byte_enum_array
 #[no_mangle]
 pub fn byte_enum_array() {
-    // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [Init::Memset; 4];
     opaque(&x);
@@ -48,7 +48,7 @@ pub fn byte_enum_array() {
 // CHECK-LABEL: @zeroed_integer_array
 #[no_mangle]
 pub fn zeroed_integer_array() {
-    // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 0, i{{[0-9]+}} 16
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 0, i{{[0-9]+}} 16
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [0u32; 4];
     opaque(&x);
diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs
index efa7b6a9680..c7515ce35a3 100644
--- a/tests/codegen/slice-iter-len-eq-zero.rs
+++ b/tests/codegen/slice-iter-len-eq-zero.rs
@@ -9,7 +9,7 @@ type Demo = [u8; 3];
 #[no_mangle]
 pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
     // CHECK-NOT: sub
-    // CHECK: %[[RET:.+]] = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
+    // CHECK: %[[RET:.+]] = icmp eq ptr {{%1|%0}}, {{%1|%0}}
     // CHECK: ret i1 %[[RET]]
     y.len() == 0
 }
diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs
index c91e5bc3cd0..4d0dce7b074 100644
--- a/tests/codegen/slice-ref-equality.rs
+++ b/tests/codegen/slice-ref-equality.rs
@@ -25,7 +25,7 @@ pub fn is_zero_slice_long(data: &[u8; 456]) -> bool {
 // CHECK-LABEL: @is_zero_slice_short
 #[no_mangle]
 pub fn is_zero_slice_short(data: &[u8; 4]) -> bool {
-    // CHECK: %[[LOAD:.+]] = load i32, {{i32\*|ptr}} %{{.+}}, align 1
+    // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     &data[..] == [0; 4]
@@ -34,7 +34,7 @@ pub fn is_zero_slice_short(data: &[u8; 4]) -> bool {
 // CHECK-LABEL: @is_zero_array
 #[no_mangle]
 pub fn is_zero_array(data: &[u8; 4]) -> bool {
-    // CHECK: %[[LOAD:.+]] = load i32, {{i32\*|ptr}} %{{.+}}, align 1
+    // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     *data == [0; 4]
@@ -50,7 +50,7 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool {
 fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
     // CHECK: icmp eq [[USIZE]] %x.1, %y.1
     // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %x.1, 3
-    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i8\*|ptr}}
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
@@ -62,7 +62,7 @@ fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
 fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
     // CHECK: icmp eq [[USIZE]] %x.1, %y.1
     // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
-    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
@@ -74,7 +74,7 @@ fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
 fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool {
     // CHECK: icmp eq [[USIZE]] %x.1, %y.1
     // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
-    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
@@ -86,7 +86,7 @@ fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool {
 fn eq_slice_of_option_of_nonzero(x: &[Option<NonZeroI16>], y: &[Option<NonZeroI16>]) -> bool {
     // CHECK: icmp eq [[USIZE]] %x.1, %y.1
     // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 1
-    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i16\*|ptr}}
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
diff --git a/tests/codegen/slice_as_from_ptr_range.rs b/tests/codegen/slice_as_from_ptr_range.rs
index 0e3fefd9728..3d8ab0a4b5f 100644
--- a/tests/codegen/slice_as_from_ptr_range.rs
+++ b/tests/codegen/slice_as_from_ptr_range.rs
@@ -1,7 +1,6 @@
 // compile-flags: -O
 // only-64bit (because we're using [ui]size)
 // ignore-debug (because the assertions get in the way)
-// min-llvm-version: 15.0 (because this is a relatively new instcombine)
 
 #![crate_type = "lib"]
 #![feature(slice_from_ptr_range)]
diff --git a/tests/codegen/stores.rs b/tests/codegen/stores.rs
index 837256e5369..a8e155c4c8a 100644
--- a/tests/codegen/stores.rs
+++ b/tests/codegen/stores.rs
@@ -17,8 +17,8 @@ pub struct Bytes {
 pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
 // CHECK: [[TMP:%.+]] = alloca i32
 // CHECK: %y = alloca [4 x i8]
-// CHECK: store i32 %0, {{i32\*|ptr}} [[TMP]]
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 {{.+}}, {{i8\*|ptr}} align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
+// CHECK: store i32 %0, ptr [[TMP]]
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
     *x = y;
 }
 
@@ -29,7 +29,7 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
 pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
 // CHECK: [[TMP:%.+]] = alloca i32
 // CHECK: %y = alloca %Bytes
-// CHECK: store i32 %0, {{i32\*|ptr}} [[TMP]]
-// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 {{.+}}, {{i8\*|ptr}} align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
+// CHECK: store i32 %0, ptr [[TMP]]
+// CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
     *x = y;
 }
diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs
index 4a68403578d..7b6611f3da4 100644
--- a/tests/codegen/swap-large-types.rs
+++ b/tests/codegen/swap-large-types.rs
@@ -83,9 +83,9 @@ pub struct BigButHighlyAligned([u8; 64 * 3]);
 #[no_mangle]
 pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) {
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192)
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192)
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192)
 // CHECK-NOT: call void @llvm.memcpy
     swap(x, y)
 }
diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs
index 461dd550cd7..b8c51b08499 100644
--- a/tests/codegen/transmute-optimized.rs
+++ b/tests/codegen/transmute-optimized.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O -Z merge-functions=disabled
-// min-llvm-version: 15.0 # this test uses `ptr`s
 // ignore-debug
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index 293b0d664f6..39126b024a6 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C opt-level=0 -C no-prepopulate-passes
-// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
index d239387768e..9d34155bdd7 100644
--- a/tests/codegen/try_question_mark_nop.rs
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 15.0
 // compile-flags: -O -Z merge-functions=disabled --edition=2021
 // only-x86_64
 
diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
index 0924dda08ee..d5f53bedd54 100644
--- a/tests/codegen/unchecked_shifts.rs
+++ b/tests/codegen/unchecked_shifts.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 15.0 (LLVM 13 in CI does this differently from submodule LLVM)
 // ignore-debug (because unchecked is checked in debug)
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs
index f169988e1f5..1313e67634a 100644
--- a/tests/codegen/uninit-consts.rs
+++ b/tests/codegen/uninit-consts.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C no-prepopulate-passes
-// min-llvm-version: 15.0 (for opaque pointers)
 
 // Check that we use undef (and not zero) for uninitialized bytes in constants.
 
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index 653c5837daf..4878ae5c3b6 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -17,25 +17,25 @@ pub struct i64x4(i64, i64, i64, i64);
 #[derive(Copy, Clone)]
 pub union UnionI64x4{ a:(), b: i64x4 }
 
-// CHECK: define {{(dso_local )?}}void @test_UnionI64x4({{<4 x i64>\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4(ptr {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4(_: UnionI64x4) { loop {} }
 
 pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 }
 
-// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_(ptr {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} }
 
 pub union UnionI64x4I64{ a: i64x4, b: i64 }
 
-// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64(ptr {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} }
 
 pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) }
 
-// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple(ptr {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} }
 
@@ -65,7 +65,7 @@ pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
 
 #[repr(C)]
 pub union CUnionU128{a:u128}
-// CHECK: define {{(dso_local )?}}void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_CUnionU128(ptr {{.*}} %_1)
 #[no_mangle]
 pub fn test_CUnionU128(_: CUnionU128) { loop {} }
 
diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs
index 8ff7ba9cb64..76098bc08a3 100644
--- a/tests/codegen/vec-as-ptr.rs
+++ b/tests/codegen/vec-as-ptr.rs
@@ -4,7 +4,7 @@
 
 // Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
 // pointer is nonnull.
-// CHECK: nonnull {{i8\*|ptr}} @vec_as_ptr
+// CHECK: nonnull ptr @vec_as_ptr
 #[no_mangle]
 pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 {
     v.as_ptr()
@@ -12,7 +12,7 @@ pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 {
 
 // Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
 // pointer is nonnull.
-// CHECK: nonnull {{i8\*|ptr}} @vec_as_mut_ptr
+// CHECK: nonnull ptr @vec_as_mut_ptr
 #[no_mangle]
 pub fn vec_as_mut_ptr(v: &mut Vec<u8>) -> *mut u8 {
     v.as_mut_ptr()
diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs
index 4481a9d1e99..a5fda7b2449 100644
--- a/tests/codegen/vec-calloc.rs
+++ b/tests/codegen/vec-calloc.rs
@@ -1,7 +1,6 @@
 // compile-flags: -O -Z merge-functions=disabled
 // only-x86_64
 // ignore-debug
-// min-llvm-version: 15.0
 
 #![crate_type = "lib"]
 
diff --git a/tests/debuginfo/thread-names.rs b/tests/debuginfo/thread-names.rs
index 7a35a518946..2c5b3f272e0 100644
--- a/tests/debuginfo/thread-names.rs
+++ b/tests/debuginfo/thread-names.rs
@@ -1,15 +1,8 @@
 // compile-flags:-g
+// revisions: macos windows
 // We can't set the main thread name on Linux because it renames the process (#97191)
-// ignore-linux
-// ignore-android
-// ignore-dragonfly
-// ignore-emscripten
-// ignore-freebsd
-// ignore-haiku
-// ignore-ios
-// ignore-netbsd
-// ignore-openbsd
-// ignore-solaris
+//[macos] only-macos
+//[windows] only-windows
 // ignore-sgx
 // ignore-windows-gnu
 
diff --git a/tests/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot b/tests/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot
index 03df5c9504b..3b90aaeae42 100644
--- a/tests/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot
+++ b/tests/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot
@@ -2,5 +2,5 @@ digraph Cov_0_4 {
     graph [fontname="Courier, monospace"];
     node [fontname="Courier, monospace"];
     edge [fontname="Courier, monospace"];
-    bcb0__Cov_0_4 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br align="left"/>    19:5-19:9: @0[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:18:1 - 20:2<br align="left"/>    20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
+    bcb0__Cov_0_4 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br align="left"/>    19:5-19:9: @0[0]: Coverage::Counter(0) for $DIR/coverage_graphviz.rs:18:1 - 20:2<br align="left"/>    20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
 }
diff --git a/tests/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot b/tests/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
index c4d389b2d76..19c220e2e1d 100644
--- a/tests/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
+++ b/tests/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
@@ -2,8 +2,8 @@ digraph Cov_0_3 {
     graph [fontname="Courier, monospace"];
     node [fontname="Courier, monospace"];
     edge [fontname="Courier, monospace"];
-    bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/>    13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
-    bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/>    12:13-12:18: @4[0]: Coverage::Expression(4294967293) = 4294967294 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/>    15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
+    bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/>    13:10-13:10: @5[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
+    bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/>    12:13-12:18: @4[0]: Coverage::Expression(2) = Expression(1) + Zero for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/>    15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
     bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br align="left"/>    11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br align="left"/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>];
     bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br align="left"/>    </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>];
     bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];
diff --git a/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
index 0aece766bd5..afcfde09c02 100644
--- a/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
@@ -5,7 +5,7 @@
       let mut _0: bool;
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2;
++         Coverage::Counter(0) for /the/src/instrument_coverage.rs:20:1 - 22:2;
           _0 = const true;
           return;
       }
diff --git a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 7ec9011a526..e17c6ddc56e 100644
--- a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,12 +8,12 @@
       let mut _3: !;
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11;
++         Coverage::Counter(0) for /the/src/instrument_coverage.rs:11:1 - 11:11;
           goto -> bb1;
       }
   
       bb1: {
-+         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17;
++         Coverage::Expression(0) = Counter(0) + Counter(1) for /the/src/instrument_coverage.rs:12:5 - 13:17;
           falseUnwind -> [real: bb2, unwind: bb6];
       }
   
@@ -27,15 +27,15 @@
       }
   
       bb4: {
-+         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2;
-+         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18;
++         Coverage::Expression(2) = Expression(1) + Zero for /the/src/instrument_coverage.rs:17:1 - 17:2;
++         Coverage::Expression(1) = Expression(0) - Counter(1) for /the/src/instrument_coverage.rs:14:13 - 14:18;
           _0 = const ();
           StorageDead(_2);
           return;
       }
   
       bb5: {
-+         Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11;
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:15:10 - 15:11;
           _1 = const ();
           StorageDead(_2);
           goto -> bb1;
diff --git a/tests/run-make/coverage-llvmir/filecheck.testprog.txt b/tests/run-make/coverage-llvmir/filecheck.testprog.txt
index b3a8808df05..9d63fabd788 100644
--- a/tests/run-make/coverage-llvmir/filecheck.testprog.txt
+++ b/tests/run-make/coverage-llvmir/filecheck.testprog.txt
@@ -39,10 +39,10 @@ CHECK-NOT:    [[DEFINE_INTERNAL]]
 CHECK:        atomicrmw add ptr
 CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
 
-CHECK:        declare void @llvm.instrprof.increment({{i8\*|ptr}}, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
+CHECK:        declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
 
 WINDOWS:      define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
-WINDOWS-NEXT: %1 = load i32, {{i32\*|ptr}} @__llvm_profile_runtime
+WINDOWS-NEXT: %1 = load i32, ptr @__llvm_profile_runtime
 WINDOWS-NEXT: ret i32 %1
 WINDOWS-NEXT: }
 
diff --git a/tests/run-make/dump-ice-to-disk/Makefile b/tests/run-make/dump-ice-to-disk/Makefile
index 4f33d590237..23006fc09e2 100644
--- a/tests/run-make/dump-ice-to-disk/Makefile
+++ b/tests/run-make/dump-ice-to-disk/Makefile
@@ -3,6 +3,7 @@ include ../tools.mk
 # ignore-windows
 
 export RUSTC := $(RUSTC_ORIGINAL)
+export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
 export TMPDIR := $(TMPDIR)
 
 all:
diff --git a/tests/run-make/libtest-json/output-default.json b/tests/run-make/libtest-json/output-default.json
index ad22b66eda6..01710f59e5d 100644
--- a/tests/run-make/libtest-json/output-default.json
+++ b/tests/run-make/libtest-json/output-default.json
@@ -2,7 +2,7 @@
 { "type": "test", "event": "started", "name": "a" }
 { "type": "test", "name": "a", "event": "ok" }
 { "type": "test", "event": "started", "name": "b" }
-{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at f.rs:9:5:\nassertion failed: false\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
 { "type": "test", "event": "started", "name": "c" }
 { "type": "test", "name": "c", "event": "ok" }
 { "type": "test", "event": "started", "name": "d" }
diff --git a/tests/run-make/libtest-json/output-stdout-success.json b/tests/run-make/libtest-json/output-stdout-success.json
index ec98172eb1c..878eb6c7c26 100644
--- a/tests/run-make/libtest-json/output-stdout-success.json
+++ b/tests/run-make/libtest-json/output-stdout-success.json
@@ -2,9 +2,9 @@
 { "type": "test", "event": "started", "name": "a" }
 { "type": "test", "name": "a", "event": "ok", "stdout": "print from successful test\n" }
 { "type": "test", "event": "started", "name": "b" }
-{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at f.rs:9:5:\nassertion failed: false\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
 { "type": "test", "event": "started", "name": "c" }
-{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'c' panicked at 'assertion failed: false', f.rs:15:5\n" }
+{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'c' panicked at f.rs:15:5:\nassertion failed: false\n" }
 { "type": "test", "event": "started", "name": "d" }
 { "type": "test", "name": "d", "event": "ignored", "message": "msg" }
 { "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
diff --git a/tests/run-make/libtest-junit/output-default.xml b/tests/run-make/libtest-junit/output-default.xml
index d59e07b8ad8..58a9a28744f 100644
--- a/tests/run-make/libtest-junit/output-default.xml
+++ b/tests/run-make/libtest-junit/output-default.xml
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"/><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at 'assertion failed: false', f.rs:10:5]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"/><system-out/><system-err/></testsuite></testsuites>
+<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"/><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at f.rs:10:5:]]>&#xA;<![CDATA[assertion failed: false]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"/><system-out/><system-err/></testsuite></testsuites>
diff --git a/tests/run-make/libtest-junit/output-stdout-success.xml b/tests/run-make/libtest-junit/output-stdout-success.xml
index 0c300611e1f..723816a4acd 100644
--- a/tests/run-make/libtest-junit/output-stdout-success.xml
+++ b/tests/run-make/libtest-junit/output-stdout-success.xml
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"><system-out><![CDATA[print from successful test]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at 'assertion failed: false', f.rs:10:5]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"><system-out><![CDATA[thread 'c' panicked at 'assertion failed: false', f.rs:16:5]]>&#xA;<![CDATA[]]></system-out></testcase><system-out/><system-err/></testsuite></testsuites>
+<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"><system-out><![CDATA[print from successful test]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at f.rs:10:5:]]>&#xA;<![CDATA[assertion failed: false]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"><system-out><![CDATA[thread 'c' panicked at f.rs:16:5:]]>&#xA;<![CDATA[assertion failed: false]]>&#xA;<![CDATA[]]></system-out></testcase><system-out/><system-err/></testsuite></testsuites>
diff --git a/tests/run-make/pgo-indirect-call-promotion/filecheck-patterns.txt b/tests/run-make/pgo-indirect-call-promotion/filecheck-patterns.txt
index e19c78350e9..2b058faafcb 100644
--- a/tests/run-make/pgo-indirect-call-promotion/filecheck-patterns.txt
+++ b/tests/run-make/pgo-indirect-call-promotion/filecheck-patterns.txt
@@ -2,7 +2,7 @@ CHECK: define void @call_a_bunch_of_functions({{.*}} {
 
 # Make sure that indirect call promotion inserted a check against the most
 # frequently called function.
-CHECK: %{{.*}} = icmp eq {{void \(\)\*|ptr}} %{{.*}}, @function_called_always
+CHECK: %{{.*}} = icmp eq ptr %{{.*}}, @function_called_always
 
 # Check that the call to `function_called_always` was inlined, so that we
 # directly call `opaque_f1` from the upstream crate.
@@ -12,5 +12,5 @@ CHECK: call void @opaque_f1()
 # Same checks as above, repeated for the trait object case
 
 CHECK: define void @call_a_bunch_of_trait_methods({{.*}}
-CHECK: %{{.*}} = icmp eq {{void \(\{\}\*\)\*|ptr}} %{{.*}}, {{.*}}@foo
+CHECK: %{{.*}} = icmp eq ptr %{{.*}}, {{.*}}@foo
 CHECK: tail call void @opaque_f2()
diff --git a/tests/run-make/short-ice/Makefile b/tests/run-make/short-ice/Makefile
index 4f33d590237..23006fc09e2 100644
--- a/tests/run-make/short-ice/Makefile
+++ b/tests/run-make/short-ice/Makefile
@@ -3,6 +3,7 @@ include ../tools.mk
 # ignore-windows
 
 export RUSTC := $(RUSTC_ORIGINAL)
+export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
 export TMPDIR := $(TMPDIR)
 
 all:
diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml
index 640ed152b0d..cd453aea276 100644
--- a/tests/rustdoc-gui/rust-logo.goml
+++ b/tests/rustdoc-gui/rust-logo.goml
@@ -33,20 +33,20 @@ call-function: (
     "check-logo",
     {
         "theme": "ayu",
-        "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+        "filter": "drop-shadow(#fff 1px 0px 0px) " +
+            "drop-shadow(#fff 0px 1px 0px) " +
+            "drop-shadow(#fff -1px 0px 0px) " +
+            "drop-shadow(#fff 0px -1px 0px)",
     },
 )
 call-function: (
     "check-logo",
     {
         "theme": "dark",
-        "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
-            "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+        "filter": "drop-shadow(#fff 1px 0px 0px) " +
+            "drop-shadow(#fff 0px 1px 0px) " +
+            "drop-shadow(#fff -1px 0px 0px) " +
+            "drop-shadow(#fff 0px -1px 0px)",
     },
 )
 call-function: (
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-output-windows.stdout b/tests/rustdoc-ui/doctest/failed-doctest-output-windows.stdout
index 6c147054da3..f4bfb94e98c 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-output-windows.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-output-windows.stdout
@@ -26,7 +26,8 @@ stdout 2
 stderr:
 stderr 1
 stderr 2
-thread 'main' panicked at 'oh no', $DIR/failed-doctest-output-windows.rs:7:1
+thread 'main' panicked at $DIR/failed-doctest-output-windows.rs:7:1:
+oh no
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-output.stdout b/tests/rustdoc-ui/doctest/failed-doctest-output.stdout
index 630198a561a..840c9c5084c 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-output.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-output.stdout
@@ -26,7 +26,8 @@ stdout 2
 stderr:
 stderr 1
 stderr 2
-thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1
+thread 'main' panicked at $DIR/failed-doctest-output.rs:7:1:
+oh no
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
diff --git a/tests/rustdoc-ui/ice-bug-report-url.rs b/tests/rustdoc-ui/ice-bug-report-url.rs
index 7689d78d31f..a3fa819ab5e 100644
--- a/tests/rustdoc-ui/ice-bug-report-url.rs
+++ b/tests/rustdoc-ui/ice-bug-report-url.rs
@@ -6,7 +6,7 @@
 
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
-// normalize-stderr-test "thread.*panicked at .*, compiler.*" -> "thread panicked at 'aborting due to `-Z treat-err-as-bug`'"
+// normalize-stderr-test "thread.*panicked at compiler.*" -> ""
 // normalize-stderr-test " +\d{1,}: .*\n" -> ""
 // normalize-stderr-test " + at .*\n" -> ""
 // normalize-stderr-test ".*note: Some details are omitted.*\n" -> ""
diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr
index 7d9f05f8f4e..869fcd20fac 100644
--- a/tests/rustdoc-ui/ice-bug-report-url.stderr
+++ b/tests/rustdoc-ui/ice-bug-report-url.stderr
@@ -4,7 +4,8 @@ error: expected one of `->`, `where`, or `{`, found `<eof>`
 LL | fn wrong()
    |          ^ expected one of `->`, `where`, or `{`
 
-thread panicked at 'aborting due to `-Z treat-err-as-bug`'
+
+aborting due to `-Z treat-err-as-bug=1`
 stack backtrace:
 
 error: the compiler unexpectedly panicked. this is a bug.
diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/alias-reexport.rs
index a2a8e651caf..4003ecec21c 100644
--- a/tests/rustdoc/alias-reexport.rs
+++ b/tests/rustdoc/alias-reexport.rs
@@ -3,6 +3,7 @@
 
 #![crate_name = "foo"]
 #![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
 
 extern crate alias_reexport2;
 
diff --git a/tests/rustdoc/alias-reexport2.rs b/tests/rustdoc/alias-reexport2.rs
index 85d3cdad962..5f6357ad128 100644
--- a/tests/rustdoc/alias-reexport2.rs
+++ b/tests/rustdoc/alias-reexport2.rs
@@ -3,6 +3,7 @@
 
 #![crate_name = "foo"]
 #![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
 
 extern crate alias_reexport;
 
diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs
index 0dccb633df9..7282d09706c 100644
--- a/tests/ui/abi/stack-probes-lto.rs
+++ b/tests/ui/abi/stack-probes-lto.rs
@@ -1,13 +1,7 @@
+// revisions: x32 x64
 // run-pass
-// ignore-arm
-// ignore-aarch64
-// ignore-mips
-// ignore-mips64
-// ignore-sparc
-// ignore-sparc64
-// ignore-loongarch64
-// ignore-wasm
-// ignore-emscripten no processes
+//[x32] only-x86
+//[x64] only-x86_64
 // ignore-sgx no processes
 // ignore-musl FIXME #31506
 // ignore-fuchsia no exception handler registered for segfault
diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs
index 8137c92304d..4b8a79a4b68 100644
--- a/tests/ui/abi/stack-probes.rs
+++ b/tests/ui/abi/stack-probes.rs
@@ -1,12 +1,7 @@
+// revisions: x32 x64
 // run-pass
-// ignore-arm
-// ignore-aarch64
-// ignore-mips
-// ignore-mips64
-// ignore-sparc
-// ignore-sparc64
-// ignore-loongarch64
-// ignore-wasm
+//[x32] only-x86
+//[x64] only-x86_64
 // ignore-emscripten no processes
 // ignore-sgx no processes
 // ignore-fuchsia no exception handler registered for segfault
diff --git a/tests/ui/annotate-snippet/auxiliary/other_file.rs b/tests/ui/annotate-snippet/auxiliary/other_file.rs
new file mode 100644
index 00000000000..6f5f412d086
--- /dev/null
+++ b/tests/ui/annotate-snippet/auxiliary/other_file.rs
@@ -0,0 +1,6 @@
+pub struct WithPrivateMethod;
+
+impl WithPrivateMethod {
+    /// Private to get an error involving two files
+    fn private_method(&self) {}
+}
diff --git a/tests/ui/annotate-snippet/multiple-files.rs b/tests/ui/annotate-snippet/multiple-files.rs
new file mode 100644
index 00000000000..981cdbb10a9
--- /dev/null
+++ b/tests/ui/annotate-snippet/multiple-files.rs
@@ -0,0 +1,8 @@
+// aux-build:other_file.rs
+// compile-flags: --error-format human-annotate-rs -Z unstable-options
+
+extern crate other_file;
+
+fn main() {
+    other_file::WithPrivateMethod.private_method();
+}
diff --git a/tests/ui/annotate-snippet/multiple-files.stderr b/tests/ui/annotate-snippet/multiple-files.stderr
new file mode 100644
index 00000000000..4236ec811d0
--- /dev/null
+++ b/tests/ui/annotate-snippet/multiple-files.stderr
@@ -0,0 +1,11 @@
+error[E0624]: method `private_method` is private
+  --> $DIR/multiple-files.rs:7:35
+   |
+LL |     other_file::WithPrivateMethod.private_method();
+   |                                   ^^^^^^^^^^^^^^ private method
+   |
+  ::: $DIR/auxiliary/other_file.rs:5:5
+   |
+LL |     fn private_method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ private method defined here
+   |
diff --git a/tests/ui/asm/x86_64/issue-96797.rs b/tests/ui/asm/x86_64/issue-96797.rs
index 954f8c5ccc3..951dd949b32 100644
--- a/tests/ui/asm/x86_64/issue-96797.rs
+++ b/tests/ui/asm/x86_64/issue-96797.rs
@@ -1,6 +1,5 @@
 // build-pass
 // compile-flags: -O
-// min-llvm-version: 14.0.5
 // needs-asm-support
 // only-x86_64
 // only-linux
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
index f1f0d7e5907..5c8d64fc6cb 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
-note: the parameter type `U` must be valid for the anonymous lifetime defined here...
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
   --> $DIR/async-generics-and-bounds.rs:12:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^^^^^
+   |                  ^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics-and-bounds.rs:12:28
    |
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
   --> $DIR/async-generics-and-bounds.rs:12:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^^^^^
+   |                  ^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics-and-bounds.rs:12:28
    |
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr
index 2f05564564c..6ae73d9e3a6 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.stderr
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
-note: the parameter type `U` must be valid for the anonymous lifetime defined here...
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
   --> $DIR/async-generics.rs:9:18
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |                  ^^^^^
+   |                  ^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics.rs:9:28
    |
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
-note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
   --> $DIR/async-generics.rs:9:18
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |                  ^^^^^
+   |                  ^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics.rs:9:28
    |
diff --git a/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs b/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs
index ade386a605d..725caddae0b 100644
--- a/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs
+++ b/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs
@@ -2,7 +2,8 @@
 // be talking about `async fn`s instead.
 
 // run-fail
-// error-pattern: thread 'main' panicked at '`async fn` resumed after completion'
+// error-pattern: thread 'main' panicked
+// error-pattern: `async fn` resumed after completion
 // edition:2018
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
diff --git a/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs b/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
index b4ea4c9f686..5909c3a5ecc 100644
--- a/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
+++ b/tests/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
@@ -3,7 +3,8 @@
 
 // run-fail
 // needs-unwind
-// error-pattern: thread 'main' panicked at '`async fn` resumed after panicking'
+// error-pattern: thread 'main' panicked
+// error-pattern: `async fn` resumed after panicking
 // edition:2018
 // ignore-wasm no panic or subprocess support
 
diff --git a/tests/ui/auto-traits/issue-83857-ub.rs b/tests/ui/auto-traits/issue-83857-ub.rs
index 0a8865295c6..626e60c37f6 100644
--- a/tests/ui/auto-traits/issue-83857-ub.rs
+++ b/tests/ui/auto-traits/issue-83857-ub.rs
@@ -1,4 +1,6 @@
 #![allow(suspicious_auto_trait_impls)]
+// Tests that we don't incorrectly allow overlap between a builtin auto trait
+// impl and a user written one. See #83857 for more details
 
 struct Always<T, U>(T, U);
 unsafe impl<T, U> Send for Always<T, U> {}
diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr
index d2aef17e7f8..23a2f62d905 100644
--- a/tests/ui/auto-traits/issue-83857-ub.stderr
+++ b/tests/ui/auto-traits/issue-83857-ub.stderr
@@ -1,12 +1,12 @@
 error[E0277]: `Foo<T, U>` cannot be sent between threads safely
-  --> $DIR/issue-83857-ub.rs:20:38
+  --> $DIR/issue-83857-ub.rs:22:38
    |
 LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `Foo<T, U>`
 note: required for `Foo<T, U>` to implement `WithAssoc`
-  --> $DIR/issue-83857-ub.rs:13:15
+  --> $DIR/issue-83857-ub.rs:15:15
    |
 LL | impl<T: Send> WithAssoc for T {
    |         ----  ^^^^^^^^^     ^
diff --git a/tests/ui/binop/borrow-suggestion-109352-2.rs b/tests/ui/binop/borrow-suggestion-109352-2.rs
new file mode 100644
index 00000000000..43dab952962
--- /dev/null
+++ b/tests/ui/binop/borrow-suggestion-109352-2.rs
@@ -0,0 +1,27 @@
+struct Bar;
+
+impl std::ops::Mul for &mut Bar {
+    type Output = Bar;
+
+    fn mul(self, _rhs: Self) -> Self::Output {
+        unimplemented!()
+    }
+}
+
+fn main() {
+    let ref_mut_bar: &mut Bar = &mut Bar;
+    let ref_bar: &Bar = &Bar;
+    let owned_bar: Bar = Bar;
+
+    let _ = ref_mut_bar * ref_mut_bar;
+
+    // FIXME: we should be able to suggest borrowing both side
+    let _ = owned_bar * owned_bar;
+    //~^ ERROR cannot multiply
+    let _ = ref_bar * ref_bar;
+    //~^ ERROR cannot multiply
+    let _ = ref_bar * ref_mut_bar;
+    //~^ ERROR cannot multiply
+    let _ = ref_mut_bar * ref_bar;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/binop/borrow-suggestion-109352-2.stderr b/tests/ui/binop/borrow-suggestion-109352-2.stderr
new file mode 100644
index 00000000000..18ed08d73dd
--- /dev/null
+++ b/tests/ui/binop/borrow-suggestion-109352-2.stderr
@@ -0,0 +1,64 @@
+error[E0369]: cannot multiply `Bar` by `Bar`
+  --> $DIR/borrow-suggestion-109352-2.rs:19:23
+   |
+LL |     let _ = owned_bar * owned_bar;
+   |             --------- ^ --------- Bar
+   |             |
+   |             Bar
+   |
+note: an implementation of `Mul` might be missing for `Bar`
+  --> $DIR/borrow-suggestion-109352-2.rs:1:1
+   |
+LL | struct Bar;
+   | ^^^^^^^^^^ must implement `Mul`
+note: the trait `Mul` must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+
+error[E0369]: cannot multiply `&Bar` by `&Bar`
+  --> $DIR/borrow-suggestion-109352-2.rs:21:21
+   |
+LL |     let _ = ref_bar * ref_bar;
+   |             ------- ^ ------- &Bar
+   |             |
+   |             &Bar
+   |
+   = note: an implementation for `&mut Bar * &mut Bar` exists
+help: consider making this expression a mutable borrow
+  --> $DIR/borrow-suggestion-109352-2.rs:21:13
+   |
+LL |     let _ = ref_bar * ref_bar;
+   |             ^^^^^^^
+help: consider making this expression a mutable borrow
+  --> $DIR/borrow-suggestion-109352-2.rs:21:23
+   |
+LL |     let _ = ref_bar * ref_bar;
+   |                       ^^^^^^^
+
+error[E0369]: cannot multiply `&Bar` by `&mut Bar`
+  --> $DIR/borrow-suggestion-109352-2.rs:23:21
+   |
+LL |     let _ = ref_bar * ref_mut_bar;
+   |             ------- ^ ----------- &mut Bar
+   |             |
+   |             &Bar
+   |
+   = note: an implementation for `&mut Bar * &mut Bar` exists
+help: consider making this expression a mutable borrow
+  --> $DIR/borrow-suggestion-109352-2.rs:23:13
+   |
+LL |     let _ = ref_bar * ref_mut_bar;
+   |             ^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/borrow-suggestion-109352-2.rs:25:27
+   |
+LL |     let _ = ref_mut_bar * ref_bar;
+   |                           ^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut Bar`
+                      found reference `&Bar`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/binop/borrow-suggestion-109352.fixed b/tests/ui/binop/borrow-suggestion-109352.fixed
new file mode 100644
index 00000000000..3374a9d78b2
--- /dev/null
+++ b/tests/ui/binop/borrow-suggestion-109352.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+
+struct Foo;
+
+impl std::ops::Mul for &Foo {
+    type Output = Foo;
+
+    fn mul(self, _rhs: Self) -> Self::Output {
+        unimplemented!()
+    }
+}
+
+fn main() {
+    let ref_mut_foo: &mut Foo = &mut Foo;
+    let ref_foo: &Foo = &Foo;
+    let owned_foo: Foo = Foo;
+
+    let _ = ref_foo * ref_foo;
+    let _ = ref_foo * ref_mut_foo;
+
+    let _ = &*ref_mut_foo * ref_foo;
+    //~^ ERROR cannot multiply
+    let _ = &*ref_mut_foo * &*ref_mut_foo;
+    //~^ ERROR cannot multiply
+    let _ = &*ref_mut_foo * &owned_foo;
+    //~^ ERROR cannot multiply
+}
diff --git a/tests/ui/binop/borrow-suggestion-109352.rs b/tests/ui/binop/borrow-suggestion-109352.rs
new file mode 100644
index 00000000000..4e8510e0de5
--- /dev/null
+++ b/tests/ui/binop/borrow-suggestion-109352.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+
+struct Foo;
+
+impl std::ops::Mul for &Foo {
+    type Output = Foo;
+
+    fn mul(self, _rhs: Self) -> Self::Output {
+        unimplemented!()
+    }
+}
+
+fn main() {
+    let ref_mut_foo: &mut Foo = &mut Foo;
+    let ref_foo: &Foo = &Foo;
+    let owned_foo: Foo = Foo;
+
+    let _ = ref_foo * ref_foo;
+    let _ = ref_foo * ref_mut_foo;
+
+    let _ = ref_mut_foo * ref_foo;
+    //~^ ERROR cannot multiply
+    let _ = ref_mut_foo * ref_mut_foo;
+    //~^ ERROR cannot multiply
+    let _ = ref_mut_foo * &owned_foo;
+    //~^ ERROR cannot multiply
+}
diff --git a/tests/ui/binop/borrow-suggestion-109352.stderr b/tests/ui/binop/borrow-suggestion-109352.stderr
new file mode 100644
index 00000000000..71e44f54b17
--- /dev/null
+++ b/tests/ui/binop/borrow-suggestion-109352.stderr
@@ -0,0 +1,45 @@
+error[E0369]: cannot multiply `&mut Foo` by `&Foo`
+  --> $DIR/borrow-suggestion-109352.rs:21:25
+   |
+LL |     let _ = ref_mut_foo * ref_foo;
+   |             ----------- ^ ------- &Foo
+   |             |
+   |             &mut Foo
+   |
+   = note: an implementation for `&Foo * &Foo` exists
+help: consider reborrowing this side
+   |
+LL |     let _ = &*ref_mut_foo * ref_foo;
+   |             ++
+
+error[E0369]: cannot multiply `&mut Foo` by `&mut Foo`
+  --> $DIR/borrow-suggestion-109352.rs:23:25
+   |
+LL |     let _ = ref_mut_foo * ref_mut_foo;
+   |             ----------- ^ ----------- &mut Foo
+   |             |
+   |             &mut Foo
+   |
+   = note: an implementation for `&Foo * &Foo` exists
+help: consider reborrowing both sides
+   |
+LL |     let _ = &*ref_mut_foo * &*ref_mut_foo;
+   |             ++              ++
+
+error[E0369]: cannot multiply `&mut Foo` by `&Foo`
+  --> $DIR/borrow-suggestion-109352.rs:25:25
+   |
+LL |     let _ = ref_mut_foo * &owned_foo;
+   |             ----------- ^ ---------- &Foo
+   |             |
+   |             &mut Foo
+   |
+   = note: an implementation for `&Foo * &Foo` exists
+help: consider reborrowing this side
+   |
+LL |     let _ = &*ref_mut_foo * &owned_foo;
+   |             ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/codegen/issue-55976.rs b/tests/ui/codegen/issue-55976.rs
index 3142704b78c..fee54fc6206 100644
--- a/tests/ui/codegen/issue-55976.rs
+++ b/tests/ui/codegen/issue-55976.rs
@@ -1,7 +1,5 @@
 // run-pass
 // ^-- The above is needed as this issue is related to LLVM/codegen.
-// min-llvm-version:15.0.0
-// ^-- The above is needed as this issue is fixed by the opaque pointers.
 
 fn main() {
     type_error(|x| &x);
diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.rs b/tests/ui/const-generics/late-bound-vars/in_closure.rs
index 00fb535f048..4fdf603b05f 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.rs
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.rs
@@ -8,13 +8,15 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
 // normalize-stderr-test "stack backtrace:\n" -> ""
 // normalize-stderr-test "\s\d{1,}: .*\n" -> ""
 // normalize-stderr-test "\s at .*\n" -> ""
 // normalize-stderr-test ".*note: Some details.*\n" -> ""
-// normalize-stderr-test "\n\n[ ]*\n" -> ""
+// normalize-stderr-test "\n[ ]*\n" -> ""
 // normalize-stderr-test "compiler/.*: projection" -> "projection"
+// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
+// normalize-stderr-test "error: [\s\n]*query stack during panic:\n" -> ""
 // this should run-pass
 
 #![feature(generic_const_exprs)]
diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.stderr b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
index 9dc5ea1f16a..ac406bf2bb1 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.stderr
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
@@ -1,4 +1,3 @@
-error: query stack during panic:
 #0 [mir_borrowck] borrow-checking `test::{closure#0}::{constant#1}`
 #1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{closure#0}::{constant#1}`
 #2 [mir_for_ctfe] caching mir of `test::{closure#0}::{constant#1}` for CTFE
@@ -8,5 +7,4 @@ error: query stack during panic:
 #6 [typeck] type-checking `test`
 #7 [analysis] running analysis passes on this crate
 end of query stack
-error: aborting due to previous error
-
+error: aborting due to previous error
\ No newline at end of file
diff --git a/tests/ui/const-generics/late-bound-vars/simple.rs b/tests/ui/const-generics/late-bound-vars/simple.rs
index 5d19aaf0b95..544073b5a56 100644
--- a/tests/ui/const-generics/late-bound-vars/simple.rs
+++ b/tests/ui/const-generics/late-bound-vars/simple.rs
@@ -8,13 +8,15 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
 // normalize-stderr-test "stack backtrace:\n" -> ""
 // normalize-stderr-test "\s\d{1,}: .*\n" -> ""
 // normalize-stderr-test "\s at .*\n" -> ""
 // normalize-stderr-test ".*note: Some details.*\n" -> ""
 // normalize-stderr-test "\n\n[ ]*\n" -> ""
 // normalize-stderr-test "compiler/.*: projection" -> "projection"
+// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
+// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack"
 
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.rs b/tests/ui/consts/const-eval/const-eval-query-stack.rs
index 81f28c1755d..4eaff494783 100644
--- a/tests/ui/consts/const-eval/const-eval-query-stack.rs
+++ b/tests/ui/consts/const-eval/const-eval-query-stack.rs
@@ -5,12 +5,12 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
 // normalize-stderr-test "stack backtrace:\n" -> ""
 // normalize-stderr-test "\s\d{1,}: .*\n" -> ""
 // normalize-stderr-test "\s at .*\n" -> ""
 // normalize-stderr-test ".*note: Some details.*\n" -> ""
-
+// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
 #![allow(unconditional_panic)]
 
 const X: i32 = 1 / 0; //~ERROR constant
diff --git a/tests/ui/consts/const-eval/nonnull_as_ref.rs b/tests/ui/consts/const-eval/nonnull_as_ref.rs
new file mode 100644
index 00000000000..eb4683e2c30
--- /dev/null
+++ b/tests/ui/consts/const-eval/nonnull_as_ref.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+use std::ptr::NonNull;
+
+const NON_NULL: NonNull<u8> = unsafe { NonNull::new_unchecked((&42u8 as *const u8).cast_mut()) };
+const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() });
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs
new file mode 100644
index 00000000000..3b48e972923
--- /dev/null
+++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs
@@ -0,0 +1,6 @@
+use std::ptr::NonNull;
+
+const NON_NULL: NonNull<u8> = unsafe { NonNull::dangling() };
+const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() });
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr
new file mode 100644
index 00000000000..de93cb0c3ca
--- /dev/null
+++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr
@@ -0,0 +1,16 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+   |
+   = note: dereferencing pointer failed: 0x1[noalloc] is a dangling pointer (it has no provenance)
+   |
+note: inside `NonNull::<u8>::as_ref::<'_>`
+  --> $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+note: inside `_`
+  --> $DIR/nonnull_as_ref_ub.rs:4:39
+   |
+LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() });
+   |                                       ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/precise-drop-with-promoted.rs b/tests/ui/consts/precise-drop-with-promoted.rs
index 5da325afb72..0c0514dd9d5 100644
--- a/tests/ui/consts/precise-drop-with-promoted.rs
+++ b/tests/ui/consts/precise-drop-with-promoted.rs
@@ -3,7 +3,7 @@
 // known-bug: #103507
 // failure-status: 101
 // normalize-stderr-test "note: .*\n\n" -> ""
-// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
 // normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
 // rustc-env:RUST_BACKTRACE=0
 
diff --git a/tests/ui/dyn-star/llvm-old-style-ptrs.rs b/tests/ui/dyn-star/llvm-old-style-ptrs.rs
deleted file mode 100644
index 4c042a53979..00000000000
--- a/tests/ui/dyn-star/llvm-old-style-ptrs.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// run-pass
-// compile-flags: -Copt-level=0 -Cllvm-args=-opaque-pointers=0
-
-// (opaque-pointers flag is called force-opaque-pointers in LLVM 13...)
-// min-llvm-version: 14.0
-// (the ability to disable opaque pointers has been removed in LLVM 17)
-// ignore-llvm-version: 17 - 99
-
-// This test can be removed once non-opaque pointers are gone from LLVM, maybe.
-
-#![feature(dyn_star, pointer_like_trait)]
-#![allow(incomplete_features)]
-
-use std::fmt::Debug;
-use std::marker::PointerLike;
-
-fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
-    t as _
-}
-
-fn main() {
-    println!("{:?}", make_dyn_star(Box::new(1i32)));
-    println!("{:?}", make_dyn_star(2usize));
-    println!("{:?}", make_dyn_star((3usize,)));
-}
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs
index dacbc93dec8..34330ed8cba 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.rs
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs
@@ -11,13 +11,16 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
 // normalize-stderr-test "stack backtrace:\n" -> ""
 // normalize-stderr-test "\s\d{1,}: .*\n" -> ""
 // normalize-stderr-test "\s at .*\n" -> ""
 // normalize-stderr-test ".*note: Some details.*\n" -> ""
 // normalize-stderr-test "\n\n[ ]*\n" -> ""
 // normalize-stderr-test "compiler/.*: projection" -> "projection"
+// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
+// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack"
+// normalize-stderr-test "[\n\s]*\nquery stack during panic:" -> "query stack during panic:"
 // edition:2018
 
 #![feature(type_alias_impl_trait)]
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
index 3187be3334c..2538eb46dfa 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
@@ -1,9 +1,9 @@
 error: 
-  --> $DIR/issue-90014-tait2.rs:41:27
+  --> $DIR/issue-90014-tait2.rs:44:27
    |
 LL |     fn make_fut(&self) -> Box<dyn for<'a> Trait<'a, Thing = Fut<'a>>> {
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^query stack during panic:
-#0 [typeck] type-checking `<impl at $DIR/issue-90014-tait2.rs:40:1: 40:13>::make_fut`
+#0 [typeck] type-checking `<impl at $DIR/issue-90014-tait2.rs:43:1: 43:13>::make_fut`
 #1 [type_of] computing type of `Fut::{opaque#0}`
 #2 [check_mod_item_types] checking item types in top-level module
 #3 [analysis] running analysis passes on this crate
diff --git a/tests/ui/generics/issue-94923.rs b/tests/ui/generics/issue-94923.rs
index d337a5dffc9..893bac0d5e8 100644
--- a/tests/ui/generics/issue-94923.rs
+++ b/tests/ui/generics/issue-94923.rs
@@ -1,6 +1,5 @@
 // run-pass
 // regression test for issue #94923
-// min-llvm-version: 15.0.0
 // compile-flags: -C opt-level=3
 
 fn f0<T>(mut x: usize) -> usize {
diff --git a/tests/ui/higher-ranked/trait-bounds/future.rs b/tests/ui/higher-ranked/trait-bounds/future.rs
index da7ee034329..61d86a9cb23 100644
--- a/tests/ui/higher-ranked/trait-bounds/future.rs
+++ b/tests/ui/higher-ranked/trait-bounds/future.rs
@@ -7,7 +7,7 @@
 //[classic] build-fail
 //[classic] failure-status: 101
 //[classic] normalize-stderr-test "note: .*\n\n" -> ""
-//[classic] normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+//[classic] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
 //[classic] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
 //[classic] rustc-env:RUST_BACKTRACE=0
 
diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr
index 55923cc5f6f..5ed0d9fcf1e 100644
--- a/tests/ui/hygiene/panic-location.run.stderr
+++ b/tests/ui/hygiene/panic-location.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:534:5
+thread 'main' panicked at library/alloc/src/raw_vec.rs:534:5:
+capacity overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/impl-trait/auto-trait-leak b/tests/ui/impl-trait/auto-trait-leak
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/tests/ui/impl-trait/auto-trait-leak
+++ /dev/null
diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.rs b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
index 970d84120e0..212e7b10802 100644
--- a/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
+++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
@@ -6,7 +6,8 @@
 
 fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
     Thunk::new(|mut cont| {
-        cont.reify_as(); //~ ERROR type annotations needed
+        //~^ ERROR type annotations needed
+        cont.reify_as();
         cont
     })
 }
@@ -15,7 +16,8 @@ type Tait = impl FnOnce(Continuation) -> Continuation;
 
 fn reify_as_tait() -> Thunk<Tait> {
     Thunk::new(|mut cont| {
-        cont.reify_as(); //~ ERROR type annotations needed
+        //~^ ERROR type annotations needed
+        cont.reify_as();
         cont
     })
 }
diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr
index 957052feba9..39bf2214232 100644
--- a/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr
+++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr
@@ -1,14 +1,30 @@
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:9:9
+  --> $DIR/hidden-type-is-opaque-2.rs:8:17
    |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^
+LL |
 LL |         cont.reify_as();
-   |         ^^^^ cannot infer type
+   |         ---- type must be known at this point
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     Thunk::new(|mut cont: /* Type */| {
+   |                         ++++++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:18:9
+  --> $DIR/hidden-type-is-opaque-2.rs:18:17
    |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^
+LL |
 LL |         cont.reify_as();
-   |         ^^^^ cannot infer type
+   |         ---- type must be known at this point
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     Thunk::new(|mut cont: /* Type */| {
+   |                         ++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs
new file mode 100644
index 00000000000..2a61c5cc8df
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs
@@ -0,0 +1,29 @@
+// check-pass
+// edition: 2021
+// issue: 113796
+
+#![feature(async_fn_in_trait)]
+
+trait AsyncLendingIterator {
+    type Item<'a>
+    where
+        Self: 'a;
+
+    async fn next(&mut self) -> Option<Self::Item<'_>>;
+}
+
+struct Lend<I>(I);
+impl<I> AsyncLendingIterator for Lend<I> {
+    type Item<'a> = &'a I
+    where
+        Self: 'a;
+
+    // Checking that the synthetic `<Self as AsyncLendingIterator>::next()` GAT
+    // is well-formed requires being able to assume the WF types of `next`.
+
+    async fn next(&mut self) -> Option<Self::Item<'_>> {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
index 8b97336fe0c..ff7ad4bf389 100644
--- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
+++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
@@ -17,7 +17,6 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
     //~^ ERROR impl has stricter requirements than trait
 
     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
-        //~^ ERROR the type `&'a I` does not fulfill the required lifetime
         (*self).iter()
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
index 54a08c5b516..106b8a7c804 100644
--- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
+++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
@@ -12,19 +12,6 @@ help: copy the `where` clause predicates from the trait
 LL |     where Self: 'b;
    |     ~~~~~~~~~~~~~~
 
-error[E0477]: the type `&'a I` does not fulfill the required lifetime
-  --> $DIR/bad-item-bound-within-rpitit.rs:19:23
-   |
-LL |     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must outlive the anonymous lifetime as defined here
-  --> $DIR/bad-item-bound-within-rpitit.rs:10:28
-   |
-LL |     fn iter(&self) -> impl '_ + Iterator<Item = Self::Item<'_>>;
-   |                            ^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0276, E0477.
-For more information about an error, try `rustc --explain E0276`.
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs
new file mode 100644
index 00000000000..742537ffcc4
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs
@@ -0,0 +1,10 @@
+#![feature(return_position_impl_trait_in_trait)]
+
+struct Wrapper<G: Send>(G);
+
+trait Foo {
+    fn bar() -> Wrapper<impl Sized>;
+    //~^ ERROR `impl Sized` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr
new file mode 100644
index 00000000000..dee87d08238
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr
@@ -0,0 +1,16 @@
+error[E0277]: `impl Sized` cannot be sent between threads safely
+  --> $DIR/check-wf-on-non-defaulted-rpitit.rs:6:17
+   |
+LL |     fn bar() -> Wrapper<impl Sized>;
+   |                 ^^^^^^^^^^^^^^^^^^^ `impl Sized` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `impl Sized`
+note: required by a bound in `Wrapper`
+  --> $DIR/check-wf-on-non-defaulted-rpitit.rs:3:19
+   |
+LL | struct Wrapper<G: Send>(G);
+   |                   ^^^^ required by this bound in `Wrapper`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
index 0558d95128f..25133214dc6 100644
--- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
@@ -1,5 +1,5 @@
 // edition:2021
-// known-bug: #108304
+// check-pass
 
 #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr
deleted file mode 100644
index b5fc9d44d36..00000000000
--- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/default-body-with-rpit.rs:11:9
-   |
-LL |         ""
-   |         ^^ expected `impl Debug`, got `&'static str`
-   |
-note: previous use here
-  --> $DIR/default-body-with-rpit.rs:10:39
-   |
-LL |       async fn baz(&self) -> impl Debug {
-   |  _______________________________________^
-LL | |         ""
-LL | |     }
-   | |_____^
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/default-body-with-rpit.rs:10:28
-   |
-LL |     async fn baz(&self) -> impl Debug {
-   |                            ^^^^^^^^^^ cannot resolve opaque type
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr
index beac6620911..4d60b133048 100644
--- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr
+++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr
@@ -47,10 +47,6 @@ note: required by a bound in `NeedsDisplay`
    |
 LL | struct NeedsDisplay<T: Display>(T);
    |                        ^^^^^^^ required by this bound in `NeedsDisplay`
-help: consider restricting type parameter `T`
-   |
-LL |     fn nya4<T: std::fmt::Display>() -> impl Wf<NeedsDisplay<T>>;
-   |              +++++++++++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/impl-trait/issues/issue-86800.rs b/tests/ui/impl-trait/issues/issue-86800.rs
index ec4fda322d0..df70b324c5e 100644
--- a/tests/ui/impl-trait/issues/issue-86800.rs
+++ b/tests/ui/impl-trait/issues/issue-86800.rs
@@ -5,7 +5,7 @@
 // error-pattern: aborting due to `-Z treat-err-as-bug=1`
 // failure-status:101
 // normalize-stderr-test ".*note: .*\n\n" -> ""
-// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
 // rustc-env:RUST_BACKTRACE=0
 
 use std::future::Future;
diff --git a/tests/ui/imports/issue-81413.rs b/tests/ui/imports/issue-81413.rs
new file mode 100644
index 00000000000..f3fb8bfab20
--- /dev/null
+++ b/tests/ui/imports/issue-81413.rs
@@ -0,0 +1,23 @@
+pub const ITEM: Item = Item;
+
+pub struct Item;
+
+pub fn item() {}
+
+pub use doesnt_exist::*;
+//~^ ERROR unresolved import `doesnt_exist`
+mod a {
+    use crate::{item, Item, ITEM};
+}
+
+mod b {
+    use crate::item;
+    use crate::Item;
+    use crate::ITEM;
+}
+
+mod c {
+    use crate::item;
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-81413.stderr b/tests/ui/imports/issue-81413.stderr
new file mode 100644
index 00000000000..e2dfe02bc85
--- /dev/null
+++ b/tests/ui/imports/issue-81413.stderr
@@ -0,0 +1,11 @@
+error[E0432]: unresolved import `doesnt_exist`
+  --> $DIR/issue-81413.rs:7:9
+   |
+LL | pub use doesnt_exist::*;
+   |         ^^^^^^^^^^^^ maybe a missing crate `doesnt_exist`?
+   |
+   = help: consider adding `extern crate doesnt_exist` to use the `doesnt_exist` crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
index 463cd52c5aa..69c7491b2af 100644
--- a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
+++ b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:6:6
+thread 'main' panicked at $DIR/const-eval-select-backtrace-std.rs:6:6:
+byte index 1 is out of bounds of ``
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/intrinsics/const-eval-select-backtrace.run.stderr b/tests/ui/intrinsics/const-eval-select-backtrace.run.stderr
index 54e28db5e53..3f196bd8abc 100644
--- a/tests/ui/intrinsics/const-eval-select-backtrace.run.stderr
+++ b/tests/ui/intrinsics/const-eval-select-backtrace.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:17:9
+thread 'main' panicked at $DIR/const-eval-select-backtrace.rs:17:9:
+Aaah!
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/issues/issue-87707.run.stderr b/tests/ui/issues/issue-87707.run.stderr
index 527c78ba89e..255a77a6ab1 100644
--- a/tests/ui/issues/issue-87707.run.stderr
+++ b/tests/ui/issues/issue-87707.run.stderr
@@ -1,3 +1,5 @@
-thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:14:24
+thread 'main' panicked at $DIR/issue-87707.rs:14:24:
+Here Once instance is poisoned.
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:16:7
+thread 'main' panicked at $DIR/issue-87707.rs:16:7:
+Once instance has previously been poisoned
diff --git a/tests/ui/layout/valid_range_oob.stderr b/tests/ui/layout/valid_range_oob.stderr
index a3a514fb830..d56804a35a7 100644
--- a/tests/ui/layout/valid_range_oob.stderr
+++ b/tests/ui/layout/valid_range_oob.stderr
@@ -1,3 +1,4 @@
+257 > 255
 error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
diff --git a/tests/ui/type-alias/lazy-type-alias-enum-variant.rs b/tests/ui/lazy-type-alias/enum-variant.rs
index 78c3159d1c2..6d18e9eca62 100644
--- a/tests/ui/type-alias/lazy-type-alias-enum-variant.rs
+++ b/tests/ui/lazy-type-alias/enum-variant.rs
@@ -2,6 +2,7 @@
 // check-pass
 
 #![feature(lazy_type_alias)]
+//~^ WARN the feature `lazy_type_alias` is incomplete and may not be safe to use
 
 enum Enum {
     Unit,
diff --git a/tests/ui/lazy-type-alias/enum-variant.stderr b/tests/ui/lazy-type-alias/enum-variant.stderr
new file mode 100644
index 00000000000..4360db91778
--- /dev/null
+++ b/tests/ui/lazy-type-alias/enum-variant.stderr
@@ -0,0 +1,11 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/enum-variant.rs:4:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs b/tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs
new file mode 100644
index 00000000000..d0abd3ebf24
--- /dev/null
+++ b/tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs
@@ -0,0 +1,14 @@
+// Check that we don't issue the lint `type_alias_bounds` for
+// lazy type aliases since the bounds are indeed enforced.
+
+// check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+#![deny(type_alias_bounds)]
+
+use std::ops::Mul;
+
+type Alias<T: Mul> = <T as Mul>::Output;
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.rs b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.rs
new file mode 100644
index 00000000000..c798e4e4368
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.rs
@@ -0,0 +1,8 @@
+// Test that we check lazy type aliases for well-formedness.
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias<T> = <T as std::ops::Mul>::Output; //~ ERROR cannot multiply `T` by `T`
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr
new file mode 100644
index 00000000000..d022f825140
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr
@@ -0,0 +1,14 @@
+error[E0277]: cannot multiply `T` by `T`
+  --> $DIR/unsatisfied-bounds-type-alias-body.rs:6:17
+   |
+LL | type Alias<T> = <T as std::ops::Mul>::Output;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T * T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type Alias<T: std::ops::Mul> = <T as std::ops::Mul>::Output;
+   |             +++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lexer/lex-emoji-identifiers.rs b/tests/ui/lexer/lex-emoji-identifiers.rs
index 91b5929c0fe..decf2f00587 100644
--- a/tests/ui/lexer/lex-emoji-identifiers.rs
+++ b/tests/ui/lexer/lex-emoji-identifiers.rs
@@ -1,9 +1,7 @@
 fn invalid_emoji_usages() {
     let arrow↔️ = "basic emoji"; //~ ERROR: identifiers cannot contain emoji
-    // FIXME
-    let planet🪐 = "basic emoji"; //~ ERROR: unknown start of token
-    // FIXME
-    let wireless🛜 = "basic emoji"; //~ ERROR: unknown start of token
+    let planet🪐 = "basic emoji"; //~ ERROR: identifiers cannot contain emoji
+    let wireless🛜 = "basic emoji"; //~ ERROR: identifiers cannot contain emoji
     // FIXME
     let key1️⃣ = "keycap sequence"; //~ ERROR: unknown start of token
                                     //~^ WARN: identifier contains uncommon Unicode codepoints
diff --git a/tests/ui/lexer/lex-emoji-identifiers.stderr b/tests/ui/lexer/lex-emoji-identifiers.stderr
index 6237c5d0236..747825fa2a9 100644
--- a/tests/ui/lexer/lex-emoji-identifiers.stderr
+++ b/tests/ui/lexer/lex-emoji-identifiers.stderr
@@ -1,17 +1,5 @@
-error: unknown start of token: \u{1fa90}
-  --> $DIR/lex-emoji-identifiers.rs:4:15
-   |
-LL |     let planet🪐 = "basic emoji";
-   |               ^^
-
-error: unknown start of token: \u{1f6dc}
-  --> $DIR/lex-emoji-identifiers.rs:6:17
-   |
-LL |     let wireless🛜 = "basic emoji";
-   |                 ^^
-
 error: unknown start of token: \u{20e3}
-  --> $DIR/lex-emoji-identifiers.rs:8:14
+  --> $DIR/lex-emoji-identifiers.rs:6:14
    |
 LL |     let key1️⃣ = "keycap sequence";
    |             ^
@@ -22,26 +10,38 @@ error: identifiers cannot contain emoji: `arrow↔️`
 LL |     let arrow↔️ = "basic emoji";
    |         ^^^^^^
 
+error: identifiers cannot contain emoji: `planet🪐`
+  --> $DIR/lex-emoji-identifiers.rs:3:9
+   |
+LL |     let planet🪐 = "basic emoji";
+   |         ^^^^^^^^
+
+error: identifiers cannot contain emoji: `wireless🛜`
+  --> $DIR/lex-emoji-identifiers.rs:4:9
+   |
+LL |     let wireless🛜 = "basic emoji";
+   |         ^^^^^^^^^^
+
 error: identifiers cannot contain emoji: `flag🇺🇳`
-  --> $DIR/lex-emoji-identifiers.rs:10:9
+  --> $DIR/lex-emoji-identifiers.rs:8:9
    |
 LL |     let flag🇺🇳 = "flag sequence";
    |         ^^^^^^
 
 error: identifiers cannot contain emoji: `wales🏴`
-  --> $DIR/lex-emoji-identifiers.rs:11:9
+  --> $DIR/lex-emoji-identifiers.rs:9:9
    |
 LL |     let wales🏴 = "tag sequence";
    |         ^^^^^^^
 
 error: identifiers cannot contain emoji: `folded🙏🏿`
-  --> $DIR/lex-emoji-identifiers.rs:12:9
+  --> $DIR/lex-emoji-identifiers.rs:10:9
    |
 LL |     let folded🙏🏿 = "modifier sequence";
    |         ^^^^^^^^^^
 
 warning: identifier contains uncommon Unicode codepoints
-  --> $DIR/lex-emoji-identifiers.rs:8:9
+  --> $DIR/lex-emoji-identifiers.rs:6:9
    |
 LL |     let key1️⃣ = "keycap sequence";
    |         ^^^^
diff --git a/tests/ui/limits/issue-17913.stderr b/tests/ui/limits/issue-17913.stderr
index 684db53a919..0d21a42883e 100644
--- a/tests/ui/limits/issue-17913.stderr
+++ b/tests/ui/limits/issue-17913.stderr
@@ -1,4 +1,5 @@
 error: values of the type `[&usize; usize::MAX]` are too big for the current architecture
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
 
 error: aborting due to previous error
 
diff --git a/tests/ui/macros/assert-eq-macro-msg.rs b/tests/ui/macros/assert-eq-macro-msg.rs
index accbd2d1e7f..cb21d5e7ed6 100644
--- a/tests/ui/macros/assert-eq-macro-msg.rs
+++ b/tests/ui/macros/assert-eq-macro-msg.rs
@@ -1,7 +1,7 @@
 // run-fail
-// error-pattern:panicked at 'assertion failed: `(left == right)`
+// error-pattern:assertion failed: `(left == right)`
 // error-pattern: left: `2`
-// error-pattern:right: `3`: 1 + 1 definitely should be 3'
+// error-pattern:right: `3`: 1 + 1 definitely should be 3
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/macros/assert-macro-explicit.rs b/tests/ui/macros/assert-macro-explicit.rs
index 578ef563278..3d1a9a6b1ad 100644
--- a/tests/ui/macros/assert-macro-explicit.rs
+++ b/tests/ui/macros/assert-macro-explicit.rs
@@ -1,5 +1,5 @@
 // run-fail
-// error-pattern:panicked at 'assertion failed: false'
+// error-pattern:assertion failed: false
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/macros/assert-macro-fmt.rs b/tests/ui/macros/assert-macro-fmt.rs
index b8d319d85f4..ceec53ceb9f 100644
--- a/tests/ui/macros/assert-macro-fmt.rs
+++ b/tests/ui/macros/assert-macro-fmt.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-assert-fmt 42 rust'
+// error-pattern: panicked
+// error-pattern: test-assert-fmt 42 rust
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/macros/assert-macro-owned.rs b/tests/ui/macros/assert-macro-owned.rs
index 753675872b9..fb4b389b80b 100644
--- a/tests/ui/macros/assert-macro-owned.rs
+++ b/tests/ui/macros/assert-macro-owned.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-assert-owned'
+// error-pattern:panicked
+// error-pattern:test-assert-owned
 // ignore-emscripten no processes
 
 #![allow(non_fmt_panics)]
diff --git a/tests/ui/macros/assert-macro-static.rs b/tests/ui/macros/assert-macro-static.rs
index dc5274a7e88..fccc3259281 100644
--- a/tests/ui/macros/assert-macro-static.rs
+++ b/tests/ui/macros/assert-macro-static.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-assert-static'
+// error-pattern:panicked
+// error-pattern:test-assert-static
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/macros/assert-matches-macro-msg.rs b/tests/ui/macros/assert-matches-macro-msg.rs
index fd8cd5a1a05..0f63de6cfff 100644
--- a/tests/ui/macros/assert-matches-macro-msg.rs
+++ b/tests/ui/macros/assert-matches-macro-msg.rs
@@ -1,7 +1,7 @@
 // run-fail
-// error-pattern:panicked at 'assertion failed: `(left matches right)`
+// error-pattern:assertion failed: `(left matches right)`
 // error-pattern: left: `2`
-// error-pattern:right: `3`: 1 + 1 definitely should be 3'
+// error-pattern:right: `3`: 1 + 1 definitely should be 3
 // ignore-emscripten no processes
 
 #![feature(assert_matches)]
diff --git a/tests/ui/macros/assert-ne-macro-msg.rs b/tests/ui/macros/assert-ne-macro-msg.rs
index fc0472b99b4..7e390d24a23 100644
--- a/tests/ui/macros/assert-ne-macro-msg.rs
+++ b/tests/ui/macros/assert-ne-macro-msg.rs
@@ -1,7 +1,7 @@
 // run-fail
-// error-pattern:panicked at 'assertion failed: `(left != right)`
+// error-pattern:assertion failed: `(left != right)`
 // error-pattern: left: `2`
-// error-pattern:right: `2`: 1 + 1 definitely should not be 2'
+// error-pattern:right: `2`: 1 + 1 definitely should not be 2
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/mir/validate/storage-live.stderr b/tests/ui/mir/validate/storage-live.stderr
index 720fb0a90b0..1037ddc88ef 100644
--- a/tests/ui/mir/validate/storage-live.stderr
+++ b/tests/ui/mir/validate/storage-live.stderr
@@ -5,6 +5,7 @@ error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH
 LL |             StorageLive(a);
    |             ^^^^^^^^^^^^^^
 
+aborting due to `-Z treat-err-as-bug=1`
 error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
diff --git a/tests/ui/mismatched_types/closure-ref-114180.rs b/tests/ui/mismatched_types/closure-ref-114180.rs
new file mode 100644
index 00000000000..d84bdbedaf6
--- /dev/null
+++ b/tests/ui/mismatched_types/closure-ref-114180.rs
@@ -0,0 +1,8 @@
+// check-fail
+
+fn main() {
+    let mut v = vec![(1,)];
+    let compare = |(a,), (e,)| todo!();
+    v.sort_by(compare);
+    //~^ ERROR type mismatch in closure arguments
+}
diff --git a/tests/ui/mismatched_types/closure-ref-114180.stderr b/tests/ui/mismatched_types/closure-ref-114180.stderr
new file mode 100644
index 00000000000..8a146d784e2
--- /dev/null
+++ b/tests/ui/mismatched_types/closure-ref-114180.stderr
@@ -0,0 +1,22 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-ref-114180.rs:6:15
+   |
+LL |     let compare = |(a,), (e,)| todo!();
+   |                   ------------ found signature defined here
+LL |     v.sort_by(compare);
+   |       ------- ^^^^^^^ expected due to this
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = note: expected closure signature `for<'a, 'b> fn(&'a ({integer},), &'b ({integer},)) -> _`
+              found closure signature `fn((_,), (_,)) -> _`
+note: required by a bound in `slice::<impl [T]>::sort_by`
+  --> $SRC_DIR/alloc/src/slice.rs:LL:COL
+help: consider adjusting the signature so it borrows its arguments
+   |
+LL |     let compare = |&(a,), &(e,)| todo!();
+   |                    +      +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/tests/ui/mismatched_types/ref-pat-suggestions.stderr b/tests/ui/mismatched_types/ref-pat-suggestions.stderr
index 62824004db5..148ed00b01d 100644
--- a/tests/ui/mismatched_types/ref-pat-suggestions.stderr
+++ b/tests/ui/mismatched_types/ref-pat-suggestions.stderr
@@ -103,10 +103,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:11:23
    |
 LL |     let _: fn(u32) = |&_a| ();
-   |                       ^--
-   |                       ||
-   |                       |expected due to this
+   |                       ^^^
+   |                       |
    |                       expected `u32`, found `&_`
+   |                       expected due to this
    |
    = note:   expected type `u32`
            found reference `&_`
@@ -120,10 +120,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:12:23
    |
 LL |     let _: fn(u32) = |&mut _a| ();
-   |                       ^^^^^--
-   |                       |    |
-   |                       |    expected due to this
+   |                       ^^^^^^^
+   |                       |
    |                       expected `u32`, found `&mut _`
+   |                       expected due to this
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
@@ -142,10 +142,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:13:25
    |
 LL |     let _: fn(&u32) = |&&_a| ();
-   |                         ^--
-   |                         ||
-   |                         |expected due to this
-   |                         expected `u32`, found `&_`
+   |                        -^^^
+   |                        ||
+   |                        |expected `u32`, found `&_`
+   |                        expected due to this
    |
    = note:   expected type `u32`
            found reference `&_`
@@ -159,10 +159,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:14:33
    |
 LL |     let _: fn(&mut u32) = |&mut &_a| ();
-   |                                 ^--
-   |                                 ||
-   |                                 |expected due to this
-   |                                 expected `u32`, found `&_`
+   |                            -----^^^
+   |                            |    |
+   |                            |    expected `u32`, found `&_`
+   |                            expected due to this
    |
    = note:   expected type `u32`
            found reference `&_`
@@ -176,10 +176,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:15:25
    |
 LL |     let _: fn(&u32) = |&&mut _a| ();
-   |                         ^^^^^--
-   |                         |    |
-   |                         |    expected due to this
-   |                         expected `u32`, found `&mut _`
+   |                        -^^^^^^^
+   |                        ||
+   |                        |expected `u32`, found `&mut _`
+   |                        expected due to this
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
@@ -193,10 +193,10 @@ error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:16:33
    |
 LL |     let _: fn(&mut u32) = |&mut &mut _a| ();
-   |                                 ^^^^^--
-   |                                 |    |
-   |                                 |    expected due to this
-   |                                 expected `u32`, found `&mut _`
+   |                            -----^^^^^^^
+   |                            |    |
+   |                            |    expected `u32`, found `&mut _`
+   |                            expected due to this
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
diff --git a/tests/ui/nll/issue-51345-2.rs b/tests/ui/nll/issue-51345-2.rs
index 52f342a8500..77a944a7b7e 100644
--- a/tests/ui/nll/issue-51345-2.rs
+++ b/tests/ui/nll/issue-51345-2.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern: thread 'main' panicked at 'explicit panic'
+// error-pattern:thread 'main' panicked
+// error-pattern:explicit panic
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/numbers-arithmetic/overflowing-add.rs b/tests/ui/numbers-arithmetic/overflowing-add.rs
index b0f22a74b4a..c45b44966ed 100644
--- a/tests/ui/numbers-arithmetic/overflowing-add.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-add.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to add with overflow'
+// error-pattern:thread 'main' panicked
+// error-pattern:attempt to add with overflow
 // compile-flags: -C debug-assertions
 // ignore-emscripten no processes
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-mul.rs b/tests/ui/numbers-arithmetic/overflowing-mul.rs
index 34ab5d8fad5..ec5279d321c 100644
--- a/tests/ui/numbers-arithmetic/overflowing-mul.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-mul.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow'
+// error-pattern:thread 'main' panicked
+// error-pattern:attempt to multiply with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
index 565b7e86fc4..dabb0d50cbb 100644
--- a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
@@ -1,5 +1,5 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
+// error-pattern:attempt to negate with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-neg.rs b/tests/ui/numbers-arithmetic/overflowing-neg.rs
index df119805303..53024375393 100644
--- a/tests/ui/numbers-arithmetic/overflowing-neg.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-neg.rs
@@ -1,5 +1,5 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
+// error-pattern:attempt to negate with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs b/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
index b59efe6f212..c2c8cad5f0b 100644
--- a/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow'
+// error-pattern:thread 'main' panicked
+// error-pattern:attempt to multiply with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs b/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
index f2643c16463..4a0f9abd982 100644
--- a/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow'
+// error-pattern:thread 'main' panicked
+// error-pattern:attempt to multiply with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-sub.rs b/tests/ui/numbers-arithmetic/overflowing-sub.rs
index 66685ac961a..119d8074802 100644
--- a/tests/ui/numbers-arithmetic/overflowing-sub.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-sub.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'attempt to subtract with overflow'
+// error-pattern:thread 'main' panicked
+// error-pattern:attempt to subtract with overflow
 // ignore-emscripten no processes
 // compile-flags: -C debug-assertions
 
diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr
index 815ce4dd015..4b00f135047 100644
--- a/tests/ui/panics/default-backtrace-ice.stderr
+++ b/tests/ui/panics/default-backtrace-ice.stderr
@@ -5,6 +5,7 @@ LL | fn main() { missing_ident; }
    |             ^^^^^^^^^^^^^ not found in this scope
 
 
+aborting due to `-Z treat-err-as-bug=1`
 stack backtrace:
 (end_short_backtrace)
 (begin_short_backtrace)
diff --git a/tests/ui/panics/fmt-only-once.run.stderr b/tests/ui/panics/fmt-only-once.run.stderr
index 39bd06881ad..a991706d34e 100644
--- a/tests/ui/panics/fmt-only-once.run.stderr
+++ b/tests/ui/panics/fmt-only-once.run.stderr
@@ -1,3 +1,4 @@
 fmt
-thread 'main' panicked at 'PrintOnFmt', $DIR/fmt-only-once.rs:20:5
+thread 'main' panicked at $DIR/fmt-only-once.rs:20:5:
+PrintOnFmt
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/issue-47429-short-backtraces.legacy.run.stderr b/tests/ui/panics/issue-47429-short-backtraces.legacy.run.stderr
index ac4ed8225bd..dce91ce59e3 100644
--- a/tests/ui/panics/issue-47429-short-backtraces.legacy.run.stderr
+++ b/tests/ui/panics/issue-47429-short-backtraces.legacy.run.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:23:5
+thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:23:5:
+explicit panic
 stack backtrace:
    0: std::panicking::begin_panic
    1: issue_47429_short_backtraces::main
diff --git a/tests/ui/panics/issue-47429-short-backtraces.v0.run.stderr b/tests/ui/panics/issue-47429-short-backtraces.v0.run.stderr
index 65401fe1c3d..f458c7acb39 100644
--- a/tests/ui/panics/issue-47429-short-backtraces.v0.run.stderr
+++ b/tests/ui/panics/issue-47429-short-backtraces.v0.run.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:23:5
+thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:23:5:
+explicit panic
 stack backtrace:
    0: std::panicking::begin_panic::<&str>
    1: issue_47429_short_backtraces::main
diff --git a/tests/ui/panics/location-detail-panic-no-column.run.stderr b/tests/ui/panics/location-detail-panic-no-column.run.stderr
index 46c9b8448d7..6d8d02a3a55 100644
--- a/tests/ui/panics/location-detail-panic-no-column.run.stderr
+++ b/tests/ui/panics/location-detail-panic-no-column.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:7:0
+thread 'main' panicked at $DIR/location-detail-panic-no-column.rs:7:0:
+column-redacted
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/location-detail-panic-no-file.run.stderr b/tests/ui/panics/location-detail-panic-no-file.run.stderr
index 811f93bf308..492ad37f5c7 100644
--- a/tests/ui/panics/location-detail-panic-no-file.run.stderr
+++ b/tests/ui/panics/location-detail-panic-no-file.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'file-redacted', <redacted>:7:5
+thread 'main' panicked at <redacted>:7:5:
+file-redacted
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/location-detail-panic-no-line.run.stderr b/tests/ui/panics/location-detail-panic-no-line.run.stderr
index cc3f1624c49..fdbc43c4311 100644
--- a/tests/ui/panics/location-detail-panic-no-line.run.stderr
+++ b/tests/ui/panics/location-detail-panic-no-line.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'line-redacted', $DIR/location-detail-panic-no-line.rs:0:5
+thread 'main' panicked at $DIR/location-detail-panic-no-line.rs:0:5:
+line-redacted
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/location-detail-panic-no-location-info.run.stderr b/tests/ui/panics/location-detail-panic-no-location-info.run.stderr
index d1c3108643c..1e9002df955 100644
--- a/tests/ui/panics/location-detail-panic-no-location-info.run.stderr
+++ b/tests/ui/panics/location-detail-panic-no-location-info.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'no location info', <redacted>:0:0
+thread 'main' panicked at <redacted>:0:0:
+no location info
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/location-detail-unwrap-no-file.run.stderr b/tests/ui/panics/location-detail-unwrap-no-file.run.stderr
index 7d8e1d93038..52019f62233 100644
--- a/tests/ui/panics/location-detail-unwrap-no-file.run.stderr
+++ b/tests/ui/panics/location-detail-unwrap-no-file.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:8:9
+thread 'main' panicked at <redacted>:8:9:
+called `Option::unwrap()` on a `None` value
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/panics/panic-macro-any-wrapped.rs b/tests/ui/panics/panic-macro-any-wrapped.rs
index 663bf6713d0..1815a0d2c10 100644
--- a/tests/ui/panics/panic-macro-any-wrapped.rs
+++ b/tests/ui/panics/panic-macro-any-wrapped.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'Box<dyn Any>'
+// error-pattern:panicked
+// error-pattern:Box<dyn Any>
 // ignore-emscripten no processes
 
 #![allow(non_fmt_panics)]
diff --git a/tests/ui/panics/panic-macro-any.rs b/tests/ui/panics/panic-macro-any.rs
index c7df5365474..1bc3c336c3f 100644
--- a/tests/ui/panics/panic-macro-any.rs
+++ b/tests/ui/panics/panic-macro-any.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'Box<dyn Any>'
+// error-pattern:panicked
+// error-pattern:Box<dyn Any>
 // ignore-emscripten no processes
 
 #![allow(non_fmt_panics)]
diff --git a/tests/ui/panics/panic-macro-explicit.rs b/tests/ui/panics/panic-macro-explicit.rs
index ac4d6f8128b..b5b6c7675ac 100644
--- a/tests/ui/panics/panic-macro-explicit.rs
+++ b/tests/ui/panics/panic-macro-explicit.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'explicit panic'
+// error-pattern:panicked
+// error-pattern:explicit panic
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/panics/panic-macro-fmt.rs b/tests/ui/panics/panic-macro-fmt.rs
index a755ebc0f4e..0796d33eae0 100644
--- a/tests/ui/panics/panic-macro-fmt.rs
+++ b/tests/ui/panics/panic-macro-fmt.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-fail-fmt 42 rust'
+// error-pattern:panicked
+// error-pattern:test-fail-fmt 42 rust
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/panics/panic-macro-owned.rs b/tests/ui/panics/panic-macro-owned.rs
index b898fde77a3..522c87e1c31 100644
--- a/tests/ui/panics/panic-macro-owned.rs
+++ b/tests/ui/panics/panic-macro-owned.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-fail-owned'
+// error-pattern:panicked
+// error-pattern:test-fail-owned
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/panics/panic-macro-static.rs b/tests/ui/panics/panic-macro-static.rs
index a1d467cbfb5..06ec5b0ad30 100644
--- a/tests/ui/panics/panic-macro-static.rs
+++ b/tests/ui/panics/panic-macro-static.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:panicked at 'test-fail-static'
+// error-pattern:panicked
+// error-pattern:test-fail-static
 // ignore-emscripten no processes
 
 fn main() {
diff --git a/tests/ui/panics/panic-set-unset-handler.rs b/tests/ui/panics/panic-set-unset-handler.rs
index dde0c72f765..91f69f0a69e 100644
--- a/tests/ui/panics/panic-set-unset-handler.rs
+++ b/tests/ui/panics/panic-set-unset-handler.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'foobar'
+// error-pattern:thread 'main' panicked
+// error-pattern:foobar
 // ignore-emscripten no processes
 
 use std::panic;
diff --git a/tests/ui/panics/panic-take-handler-nop.rs b/tests/ui/panics/panic-take-handler-nop.rs
index 41cbac97c44..d14a3244e61 100644
--- a/tests/ui/panics/panic-take-handler-nop.rs
+++ b/tests/ui/panics/panic-take-handler-nop.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'main' panicked at 'foobar'
+// error-pattern:thread 'main' panicked
+// error-pattern:foobar
 // ignore-emscripten no processes
 
 use std::panic;
diff --git a/tests/ui/panics/panic-task-name-none.rs b/tests/ui/panics/panic-task-name-none.rs
index 4e95fb5bdb8..3fb0f3412f6 100644
--- a/tests/ui/panics/panic-task-name-none.rs
+++ b/tests/ui/panics/panic-task-name-none.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread '<unnamed>' panicked at 'test'
+// error-pattern:thread '<unnamed>' panicked
+// error-pattern:test
 // ignore-emscripten Needs threads
 
 use std::thread;
diff --git a/tests/ui/panics/panic-task-name-owned.rs b/tests/ui/panics/panic-task-name-owned.rs
index f85be7bb8e2..d5274ebbc4b 100644
--- a/tests/ui/panics/panic-task-name-owned.rs
+++ b/tests/ui/panics/panic-task-name-owned.rs
@@ -1,5 +1,6 @@
 // run-fail
-// error-pattern:thread 'owned name' panicked at 'test'
+// error-pattern:thread 'owned name' panicked
+// error-pattern:test
 // ignore-emscripten Needs threads.
 
 use std::thread::Builder;
diff --git a/tests/ui/panics/runtime-switch.legacy.run.stderr b/tests/ui/panics/runtime-switch.legacy.run.stderr
index 0f76551630c..bd05b6cc00f 100644
--- a/tests/ui/panics/runtime-switch.legacy.run.stderr
+++ b/tests/ui/panics/runtime-switch.legacy.run.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:26:5
+thread 'main' panicked at $DIR/runtime-switch.rs:26:5:
+explicit panic
 stack backtrace:
    0: std::panicking::begin_panic
    1: runtime_switch::main
diff --git a/tests/ui/panics/runtime-switch.v0.run.stderr b/tests/ui/panics/runtime-switch.v0.run.stderr
index a4ae441317d..2078c356d5c 100644
--- a/tests/ui/panics/runtime-switch.v0.run.stderr
+++ b/tests/ui/panics/runtime-switch.v0.run.stderr
@@ -1,4 +1,5 @@
-thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:26:5
+thread 'main' panicked at $DIR/runtime-switch.rs:26:5:
+explicit panic
 stack backtrace:
    0: std::panicking::begin_panic::<&str>
    1: runtime_switch::main
diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
index 2592b747918..2b648a0cad2 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
+++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
@@ -1,10 +1,13 @@
-thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames-2.rs:56:5
+thread 'main' panicked at $DIR/short-ice-remove-middle-frames-2.rs:56:5:
+debug!!!
 stack backtrace:
    0: std::panicking::begin_panic
    1: short_ice_remove_middle_frames_2::eight
    2: short_ice_remove_middle_frames_2::seven::{{closure}}
+      [... omitted 3 frames ...]
    3: short_ice_remove_middle_frames_2::fifth
    4: short_ice_remove_middle_frames_2::fourth::{{closure}}
+      [... omitted 4 frames ...]
    5: short_ice_remove_middle_frames_2::first
    6: short_ice_remove_middle_frames_2::main
    7: core::ops::function::FnOnce::call_once
diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
index 9c15f2e08fe..5b372684096 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
+++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
@@ -1,9 +1,11 @@
-thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames.rs:52:5
+thread 'main' panicked at $DIR/short-ice-remove-middle-frames.rs:52:5:
+debug!!!
 stack backtrace:
    0: std::panicking::begin_panic
    1: short_ice_remove_middle_frames::seven
    2: short_ice_remove_middle_frames::sixth
    3: short_ice_remove_middle_frames::fifth::{{closure}}
+      [... omitted 4 frames ...]
    4: short_ice_remove_middle_frames::second
    5: short_ice_remove_middle_frames::first::{{closure}}
    6: short_ice_remove_middle_frames::first
diff --git a/tests/ui/parser/ternary_operator.rs b/tests/ui/parser/ternary_operator.rs
new file mode 100644
index 00000000000..23d537e77f7
--- /dev/null
+++ b/tests/ui/parser/ternary_operator.rs
@@ -0,0 +1,69 @@
+// A good chunk of these errors aren't shown to the user, but are still
+// required in the test for it to pass.
+
+fn a() { //~ NOTE this function should return `Result` or `Option` to accept `?`
+    let x = 5 > 2 ? true : false;
+    //~^ ERROR Rust has no ternary operator
+    //~| HELP use an `if-else` expression instead
+    //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277]
+    //~| HELP the trait `Try` is not implemented for `{integer}`
+    //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277]
+    //~| HELP the trait `FromResidual<_>` is not implemented for `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the `?` operator cannot be applied to type `{integer}`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE cannot use the `?` operator in a function that returns `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+}
+
+fn b() { //~ NOTE this function should return `Result` or `Option` to accept `?`
+    let x = 5 > 2 ? { true } : { false };
+    //~^ ERROR Rust has no ternary operator
+    //~| HELP use an `if-else` expression instead
+    //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277]
+    //~| HELP the trait `Try` is not implemented for `{integer}`
+    //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277]
+    //~| HELP the trait `FromResidual<_>` is not implemented for `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the `?` operator cannot be applied to type `{integer}`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE cannot use the `?` operator in a function that returns `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+}
+
+fn c() { //~ NOTE this function should return `Result` or `Option` to accept `?`
+    let x = 5 > 2 ? f32::MAX : f32::MIN;
+    //~^ ERROR Rust has no ternary operator
+    //~| HELP use an `if-else` expression instead
+    //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277]
+    //~| HELP the trait `Try` is not implemented for `{integer}`
+    //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277]
+    //~| HELP the trait `FromResidual<_>` is not implemented for `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the `?` operator cannot be applied to type `{integer}`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE cannot use the `?` operator in a function that returns `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+}
+
+fn main() { //~ NOTE this function should return `Result` or `Option` to accept `?`
+    let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
+    //~^ ERROR Rust has no ternary operator
+    //~| HELP use an `if-else` expression instead
+    //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `:`
+    //~| NOTE expected one of `.`, `;`, `?`, `else`, or an operator
+    //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277]
+    //~| HELP the trait `Try` is not implemented for `{integer}`
+    //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277]
+    //~| HELP the trait `FromResidual<_>` is not implemented for `()`
+    //~| NOTE type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the `?` operator cannot be applied to type `{integer}`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE cannot use the `?` operator in a function that returns `()`
+    //~| NOTE in this expansion of desugaring of operator `?`
+}
diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr
new file mode 100644
index 00000000000..af9565bbead
--- /dev/null
+++ b/tests/ui/parser/ternary_operator.stderr
@@ -0,0 +1,115 @@
+error: Rust has no ternary operator
+  --> $DIR/ternary_operator.rs:5:19
+   |
+LL |     let x = 5 > 2 ? true : false;
+   |                   ^^^^^^^^^^^^^^^
+   |
+   = help: use an `if-else` expression instead
+
+error: Rust has no ternary operator
+  --> $DIR/ternary_operator.rs:21:19
+   |
+LL |     let x = 5 > 2 ? { true } : { false };
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use an `if-else` expression instead
+
+error: Rust has no ternary operator
+  --> $DIR/ternary_operator.rs:37:19
+   |
+LL |     let x = 5 > 2 ? f32::MAX : f32::MIN;
+   |                   ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use an `if-else` expression instead
+
+error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:`
+  --> $DIR/ternary_operator.rs:53:37
+   |
+LL |     let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
+   |                                     ^ expected one of `.`, `;`, `?`, `else`, or an operator
+   |
+   = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+
+error: Rust has no ternary operator
+  --> $DIR/ternary_operator.rs:53:19
+   |
+LL |     let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use an `if-else` expression instead
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/ternary_operator.rs:5:17
+   |
+LL |     let x = 5 > 2 ? true : false;
+   |                 ^^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/ternary_operator.rs:5:19
+   |
+LL | fn a() {
+   | ------ this function should return `Result` or `Option` to accept `?`
+LL |     let x = 5 > 2 ? true : false;
+   |                   ^ cannot use the `?` operator in a function that returns `()`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/ternary_operator.rs:21:17
+   |
+LL |     let x = 5 > 2 ? { true } : { false };
+   |                 ^^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/ternary_operator.rs:21:19
+   |
+LL | fn b() {
+   | ------ this function should return `Result` or `Option` to accept `?`
+LL |     let x = 5 > 2 ? { true } : { false };
+   |                   ^ cannot use the `?` operator in a function that returns `()`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/ternary_operator.rs:37:17
+   |
+LL |     let x = 5 > 2 ? f32::MAX : f32::MIN;
+   |                 ^^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/ternary_operator.rs:37:19
+   |
+LL | fn c() {
+   | ------ this function should return `Result` or `Option` to accept `?`
+LL |     let x = 5 > 2 ? f32::MAX : f32::MIN;
+   |                   ^ cannot use the `?` operator in a function that returns `()`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/ternary_operator.rs:53:17
+   |
+LL |     let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
+   |                 ^^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/ternary_operator.rs:53:19
+   |
+LL | fn main() {
+   | --------- this function should return `Result` or `Option` to accept `?`
+LL |     let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
+   |                   ^ cannot use the `?` operator in a function that returns `()`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs
index eae20dd9df3..46e24915259 100644
--- a/tests/ui/privacy/unnameable_types.rs
+++ b/tests/ui/privacy/unnameable_types.rs
@@ -11,12 +11,12 @@ mod m {
 
     pub trait PubTr { //~ ERROR trait `PubTr` is reachable but cannot be named
         const C : i32 = 0;
-        type Alias; //~ ERROR associated type `PubTr::Alias` is reachable but cannot be named
+        type Alias;
         fn f() {}
     }
 
     impl PubTr for PubStruct {
-        type Alias = i32; //~ ERROR associated type `<PubStruct as PubTr>::Alias` is reachable but cannot be named
+        type Alias = i32;
         fn f() {}
     }
 }
diff --git a/tests/ui/privacy/unnameable_types.stderr b/tests/ui/privacy/unnameable_types.stderr
index 25eb5c9434a..90412752575 100644
--- a/tests/ui/privacy/unnameable_types.stderr
+++ b/tests/ui/privacy/unnameable_types.stderr
@@ -22,17 +22,5 @@ error: trait `PubTr` is reachable but cannot be named
 LL |     pub trait PubTr {
    |     ^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
 
-error: associated type `PubTr::Alias` is reachable but cannot be named
-  --> $DIR/unnameable_types.rs:14:9
-   |
-LL |         type Alias;
-   |         ^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
-
-error: associated type `<PubStruct as PubTr>::Alias` is reachable but cannot be named
-  --> $DIR/unnameable_types.rs:19:9
-   |
-LL |         type Alias = i32;
-   |         ^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/proc-macro/load-panic-backtrace.stderr b/tests/ui/proc-macro/load-panic-backtrace.stderr
index 45d4fd1c9bc..c1a642713d2 100644
--- a/tests/ui/proc-macro/load-panic-backtrace.stderr
+++ b/tests/ui/proc-macro/load-panic-backtrace.stderr
@@ -1,4 +1,5 @@
-at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5
+at $DIR/auxiliary/test-macros.rs:43:5:
+panic-derive
 error: proc-macro derive panicked
   --> $DIR/load-panic-backtrace.rs:11:10
    |
diff --git a/tests/ui/process/multi-panic.rs b/tests/ui/process/multi-panic.rs
index a1887c2180e..c240dc18fd3 100644
--- a/tests/ui/process/multi-panic.rs
+++ b/tests/ui/process/multi-panic.rs
@@ -8,10 +8,12 @@ fn check_for_no_backtrace(test: std::process::Output) {
     let err = String::from_utf8_lossy(&test.stderr);
     let mut it = err.lines();
 
-    assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked at")), Some(true));
+    assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked")), Some(true));
+    assert_eq!(it.next().is_some(), true);
     assert_eq!(it.next(), Some("note: run with `RUST_BACKTRACE=1` \
                                 environment variable to display a backtrace"));
     assert_eq!(it.next().map(|l| l.starts_with("thread 'main' panicked at")), Some(true));
+    assert_eq!(it.next().is_some(), true);
     assert_eq!(it.next(), None);
 }
 
diff --git a/tests/ui/process/println-with-broken-pipe.run.stderr b/tests/ui/process/println-with-broken-pipe.run.stderr
index ebcd920d501..a334c0ad204 100644
--- a/tests/ui/process/println-with-broken-pipe.run.stderr
+++ b/tests/ui/process/println-with-broken-pipe.run.stderr
@@ -1,2 +1,3 @@
-thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:LL:CC
+thread 'main' panicked at library/std/src/io/stdio.rs:LL:CC:
+failed printing to stdout: Broken pipe (os error 32)
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
index d3591e63a08..da27724007d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
@@ -1,5 +1,4 @@
-// known-bug: #110395
-#![feature(const_trait_impl)]
+#![feature(const_trait_impl, effects)]
 
 #[const_trait]
 pub trait Tr {
@@ -7,7 +6,7 @@ pub trait Tr {
 
     fn b(&self) {
         ().a()
-        //FIXME ~^ ERROR the trait bound
+        //~^ ERROR the trait bound
     }
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index 9f9f17b0929..fe51c1f1ca3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -1,11 +1,11 @@
-error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
    |
 LL |         ().a()
-   |            ^^^
+   |            ^ the trait `~const Tr` is not implemented for `()`
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = help: the trait `Tr` is implemented for `()`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
index 3576eed71ab..62fb5238bbd 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
@@ -27,6 +27,10 @@ extern "platform-intrinsic" {
     fn simd_xor<T>(x: T, y: T) -> T;
 
     fn simd_neg<T>(x: T) -> T;
+    fn simd_bswap<T>(x: T) -> T;
+    fn simd_bitreverse<T>(x: T) -> T;
+    fn simd_ctlz<T>(x: T) -> T;
+    fn simd_cttz<T>(x: T) -> T;
 }
 
 fn main() {
@@ -64,6 +68,14 @@ fn main() {
 
         simd_neg(x);
         simd_neg(z);
+        simd_bswap(x);
+        simd_bswap(y);
+        simd_bitreverse(x);
+        simd_bitreverse(y);
+        simd_ctlz(x);
+        simd_ctlz(y);
+        simd_cttz(x);
+        simd_cttz(y);
 
 
         simd_add(0, 0);
@@ -87,6 +99,14 @@ fn main() {
 
         simd_neg(0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
+        simd_bswap(0);
+        //~^ ERROR expected SIMD input type, found non-SIMD `i32`
+        simd_bitreverse(0);
+        //~^ ERROR expected SIMD input type, found non-SIMD `i32`
+        simd_ctlz(0);
+        //~^ ERROR expected SIMD input type, found non-SIMD `i32`
+        simd_cttz(0);
+        //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
 
         simd_shl(z, z);
@@ -99,5 +119,13 @@ fn main() {
 //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_xor(z, z);
 //~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_bswap(z);
+//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_bitreverse(z);
+//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_ctlz(z);
+//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_cttz(z);
+//~^ ERROR unsupported operation on `f32x4` with element `f32`
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
index 0f0a7ea6652..db26f3417c9 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
@@ -1,93 +1,141 @@
 error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:69:9
+  --> $DIR/generic-arithmetic-2.rs:81:9
    |
 LL |         simd_add(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:71:9
+  --> $DIR/generic-arithmetic-2.rs:83:9
    |
 LL |         simd_sub(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:73:9
+  --> $DIR/generic-arithmetic-2.rs:85:9
    |
 LL |         simd_mul(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:75:9
+  --> $DIR/generic-arithmetic-2.rs:87:9
    |
 LL |         simd_div(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:77:9
+  --> $DIR/generic-arithmetic-2.rs:89:9
    |
 LL |         simd_shl(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:79:9
+  --> $DIR/generic-arithmetic-2.rs:91:9
    |
 LL |         simd_shr(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:81:9
+  --> $DIR/generic-arithmetic-2.rs:93:9
    |
 LL |         simd_and(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:83:9
+  --> $DIR/generic-arithmetic-2.rs:95:9
    |
 LL |         simd_or(0, 0);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:85:9
+  --> $DIR/generic-arithmetic-2.rs:97:9
    |
 LL |         simd_xor(0, 0);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-arithmetic-2.rs:88:9
+  --> $DIR/generic-arithmetic-2.rs:100:9
    |
 LL |         simd_neg(0);
    |         ^^^^^^^^^^^
 
+error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-arithmetic-2.rs:102:9
+   |
+LL |         simd_bswap(0);
+   |         ^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-arithmetic-2.rs:104:9
+   |
+LL |         simd_bitreverse(0);
+   |         ^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-arithmetic-2.rs:106:9
+   |
+LL |         simd_ctlz(0);
+   |         ^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-arithmetic-2.rs:108:9
+   |
+LL |         simd_cttz(0);
+   |         ^^^^^^^^^^^^
+
 error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:92:9
+  --> $DIR/generic-arithmetic-2.rs:112:9
    |
 LL |         simd_shl(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:94:9
+  --> $DIR/generic-arithmetic-2.rs:114:9
    |
 LL |         simd_shr(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:96:9
+  --> $DIR/generic-arithmetic-2.rs:116:9
    |
 LL |         simd_and(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:98:9
+  --> $DIR/generic-arithmetic-2.rs:118:9
    |
 LL |         simd_or(z, z);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:100:9
+  --> $DIR/generic-arithmetic-2.rs:120:9
    |
 LL |         simd_xor(z, z);
    |         ^^^^^^^^^^^^^^
 
-error: aborting due to 15 previous errors
+error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:122:9
+   |
+LL |         simd_bswap(z);
+   |         ^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:124:9
+   |
+LL |         simd_bitreverse(z);
+   |         ^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:126:9
+   |
+LL |         simd_ctlz(z);
+   |         ^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:128:9
+   |
+LL |         simd_cttz(z);
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
index c507b8d31ec..f021ee4710a 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
@@ -1,8 +1,6 @@
 // run-pass
 #![allow(non_camel_case_types)]
-
 // ignore-emscripten FIXME(#45351) hits an LLVM assert
-
 #![feature(repr_simd, platform_intrinsics)]
 
 #[repr(simd)]
@@ -22,7 +20,7 @@ macro_rules! all_eq {
         let a = $a;
         let b = $b;
         assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3);
-    }}
+    }};
 }
 
 macro_rules! all_eq_ {
@@ -30,10 +28,9 @@ macro_rules! all_eq_ {
         let a = $a;
         let b = $b;
         assert!(a.0 == b.0);
-    }}
+    }};
 }
 
-
 extern "platform-intrinsic" {
     fn simd_add<T>(x: T, y: T) -> T;
     fn simd_sub<T>(x: T, y: T) -> T;
@@ -47,6 +44,10 @@ extern "platform-intrinsic" {
     fn simd_xor<T>(x: T, y: T) -> T;
 
     fn simd_neg<T>(x: T) -> T;
+    fn simd_bswap<T>(x: T) -> T;
+    fn simd_bitreverse<T>(x: T) -> T;
+    fn simd_ctlz<T>(x: T) -> T;
+    fn simd_cttz<T>(x: T) -> T;
 }
 
 fn main() {
@@ -84,8 +85,8 @@ fn main() {
         all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1]));
         all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1);
         all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0));
-        all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0));
-        all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0));
+        all_eq!(simd_div(z1, z2), f32x4(1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0));
+        all_eq!(simd_div(z2, z1), f32x4(2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0));
 
         all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0));
         all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1));
@@ -109,8 +110,10 @@ fn main() {
         // ensure we get logical vs. arithmetic shifts correct
         let (a, b, c, d) = (-12, -123, -1234, -12345);
         all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4));
-        all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1),
-                U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4]));
+        all_eq_!(
+            simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1),
+            U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4])
+        );
 
         all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4));
         all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4));
@@ -132,5 +135,19 @@ fn main() {
         all_eq!(simd_neg(z1), f32x4(-1.0, -2.0, -3.0, -4.0));
         all_eq!(simd_neg(z2), f32x4(-2.0, -3.0, -4.0, -5.0));
 
+        all_eq!(simd_bswap(x1), i32x4(0x01000000, 0x02000000, 0x03000000, 0x04000000));
+        all_eq_!(simd_bswap(y1), U32::<4>([0x01000000, 0x02000000, 0x03000000, 0x04000000]));
+
+        all_eq!(
+            simd_bitreverse(x1),
+            i32x4(0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000)
+        );
+        all_eq_!(simd_bitreverse(y1), U32::<4>([0x80000000, 0x40000000, 0xc0000000, 0x20000000]));
+
+        all_eq!(simd_ctlz(x1), i32x4(31, 30, 30, 29));
+        all_eq_!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29]));
+
+        all_eq!(simd_cttz(x1), i32x4(0, 1, 0, 2));
+        all_eq_!(simd_cttz(y1), U32::<4>([0, 1, 0, 2]));
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-bswap-byte.rs b/tests/ui/simd/intrinsic/generic-bswap-byte.rs
new file mode 100644
index 00000000000..13fc942c25a
--- /dev/null
+++ b/tests/ui/simd/intrinsic/generic-bswap-byte.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct i8x4([i8; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x4([u8; 4]);
+
+extern "platform-intrinsic" {
+    fn simd_bswap<T>(x: T) -> T;
+}
+
+fn main() {
+    unsafe {
+        assert_eq!(simd_bswap(i8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]);
+        assert_eq!(simd_bswap(u8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]);
+    }
+}
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index 8d1765eb8e9..3ebd2dbceaa 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -1,16 +1,5 @@
-// ignore-arm
-// ignore-aarch64
-// ignore-wasm
-// ignore-emscripten
-// ignore-mips
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-s390x
-// ignore-loongarch64
+// only-x86_64
+//
 // gate-test-sse4a_target_feature
 // gate-test-powerpc_target_feature
 // gate-test-avx512_target_feature
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index ee542b60a26..896212e42fc 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:32:18
+  --> $DIR/gate.rs:21:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs
index 77fd8b85f3f..d1b3cf71c15 100644
--- a/tests/ui/target-feature/invalid-attribute.rs
+++ b/tests/ui/target-feature/invalid-attribute.rs
@@ -1,16 +1,4 @@
-// ignore-arm
-// ignore-aarch64
-// ignore-wasm
-// ignore-emscripten
-// ignore-mips
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-riscv64
-// ignore-s390x
-// ignore-sparc
-// ignore-sparc64
-// ignore-loongarch64
+// only-x86_64
 
 #![warn(unused_attributes)]
 
diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr
index 6d37d0917bc..29c73921c53 100644
--- a/tests/ui/target-feature/invalid-attribute.stderr
+++ b/tests/ui/target-feature/invalid-attribute.stderr
@@ -1,11 +1,11 @@
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:32:1
+  --> $DIR/invalid-attribute.rs:20:1
    |
 LL | #[target_feature = "+sse2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:17:1
+  --> $DIR/invalid-attribute.rs:5:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL | extern crate alloc;
    | ------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:22:1
+  --> $DIR/invalid-attribute.rs:10:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | use alloc::alloc::alloc;
    | ------------------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:27:1
+  --> $DIR/invalid-attribute.rs:15:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | extern "Rust" {}
    | ---------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:49:1
+  --> $DIR/invalid-attribute.rs:37:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | mod another {}
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:54:1
+  --> $DIR/invalid-attribute.rs:42:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL | const FOO: usize = 7;
    | --------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:59:1
+  --> $DIR/invalid-attribute.rs:47:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | struct Foo;
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:64:1
+  --> $DIR/invalid-attribute.rs:52:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL | enum Bar {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:69:1
+  --> $DIR/invalid-attribute.rs:57:1
    |
 LL |   #[target_feature(enable = "sse2")]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,7 +81,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:77:1
+  --> $DIR/invalid-attribute.rs:65:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | type Uwu = ();
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:82:1
+  --> $DIR/invalid-attribute.rs:70:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | trait Baz {}
    | ------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:92:1
+  --> $DIR/invalid-attribute.rs:80:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL | static A: () = ();
    | ------------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:97:1
+  --> $DIR/invalid-attribute.rs:85:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL | impl Quux for u8 {}
    | ------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:102:1
+  --> $DIR/invalid-attribute.rs:90:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -126,7 +126,7 @@ LL | impl Foo {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:120:5
+  --> $DIR/invalid-attribute.rs:108:5
    |
 LL |       #[target_feature(enable = "sse2")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@ LL | |     }
    | |_____- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:128:5
+  --> $DIR/invalid-attribute.rs:116:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -147,25 +147,25 @@ LL |     || {};
    |     ----- not a function definition
 
 error: the feature named `foo` is not valid for this target
-  --> $DIR/invalid-attribute.rs:34:18
+  --> $DIR/invalid-attribute.rs:22:18
    |
 LL | #[target_feature(enable = "foo")]
    |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
 
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:37:18
+  --> $DIR/invalid-attribute.rs:25:18
    |
 LL | #[target_feature(bar)]
    |                  ^^^ help: must be of the form: `enable = ".."`
 
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:39:18
+  --> $DIR/invalid-attribute.rs:27:18
    |
 LL | #[target_feature(disable = "baz")]
    |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
 
 error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:43:1
+  --> $DIR/invalid-attribute.rs:31:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -177,13 +177,13 @@ LL | fn bar() {}
    = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
 
 error: cannot use `#[inline(always)]` with `#[target_feature]`
-  --> $DIR/invalid-attribute.rs:87:1
+  --> $DIR/invalid-attribute.rs:75:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
 
 error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:112:5
+  --> $DIR/invalid-attribute.rs:100:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
index 727e9691c53..8c3f5a07f56 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
@@ -1,9 +1,11 @@
-thread 'main' panicked at 'assertion failed: `(left == right)`
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:33:5:
+assertion failed: `(left == right)`
   left: `2`,
- right: `4`', $DIR/test-panic-abort-nocapture.rs:33:5
+ right: `4`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'assertion failed: `(left == right)`
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:27:5:
+assertion failed: `(left == right)`
   left: `2`,
- right: `4`', $DIR/test-panic-abort-nocapture.rs:27:5
+ right: `4`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 testing321
diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout
index b6b9c2560fe..785407dfa0b 100644
--- a/tests/ui/test-attrs/test-panic-abort.run.stdout
+++ b/tests/ui/test-attrs/test-panic-abort.run.stdout
@@ -17,9 +17,10 @@ hello, world
 testing123
 ---- it_fails stderr ----
 testing321
-thread 'main' panicked at 'assertion failed: `(left == right)`
+thread 'main' panicked at $DIR/test-panic-abort.rs:38:5:
+assertion failed: `(left == right)`
   left: `2`,
- right: `5`', $DIR/test-panic-abort.rs:38:5
+ right: `5`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
diff --git a/tests/ui/test-attrs/test-thread-capture.run.stdout b/tests/ui/test-attrs/test-thread-capture.run.stdout
index 513c8cf2add..31261aaa230 100644
--- a/tests/ui/test-attrs/test-thread-capture.run.stdout
+++ b/tests/ui/test-attrs/test-thread-capture.run.stdout
@@ -10,7 +10,8 @@ fee
 fie
 foe
 fum
-thread 'thready_fail' panicked at 'explicit panic', $DIR/test-thread-capture.rs:32:5
+thread 'thready_fail' panicked at $DIR/test-thread-capture.rs:32:5:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
diff --git a/tests/ui/test-attrs/test-thread-nocapture.run.stderr b/tests/ui/test-attrs/test-thread-nocapture.run.stderr
index 8c905d1af85..9266fe84197 100644
--- a/tests/ui/test-attrs/test-thread-nocapture.run.stderr
+++ b/tests/ui/test-attrs/test-thread-nocapture.run.stderr
@@ -1,2 +1,3 @@
-thread 'thready_fail' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:32:5
+thread 'thready_fail' panicked at $DIR/test-thread-nocapture.rs:32:5:
+explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/threads-sendsync/issue-24313.rs b/tests/ui/threads-sendsync/issue-24313.rs
index c28b4ca9601..6694bac0dc7 100644
--- a/tests/ui/threads-sendsync/issue-24313.rs
+++ b/tests/ui/threads-sendsync/issue-24313.rs
@@ -19,7 +19,7 @@ fn main() {
     if args.len() == 1 {
         let out = Command::new(&args[0]).arg("test").output().unwrap();
         let stderr = std::str::from_utf8(&out.stderr).unwrap();
-        assert!(stderr.contains("panicked at 'explicit panic'"),
+        assert!(stderr.contains("explicit panic"),
                 "bad failure message:\n{}\n", stderr);
     } else {
         // TLS dtors are not always run on process exit
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
new file mode 100644
index 00000000000..9f0993d65a7
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
+  --> $DIR/upcast-through-struct-tail.rs:10:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
new file mode 100644
index 00000000000..9f0993d65a7
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
+  --> $DIR/upcast-through-struct-tail.rs:10:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
new file mode 100644
index 00000000000..42495f45f8a
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
@@ -0,0 +1,14 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+struct Wrapper<T: ?Sized>(T);
+
+trait A: B {}
+trait B {}
+
+fn test<'a>(x: Box<Wrapper<dyn A + 'a>>) -> Box<Wrapper<dyn B + 'a>> {
+    x
+    //~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
+}
+
+fn main() {}
diff --git a/tests/ui/treat-err-as-bug/delay_span_bug.rs b/tests/ui/treat-err-as-bug/delay_span_bug.rs
index 832afddf891..533c8d1ec8f 100644
--- a/tests/ui/treat-err-as-bug/delay_span_bug.rs
+++ b/tests/ui/treat-err-as-bug/delay_span_bug.rs
@@ -3,7 +3,7 @@
 // error-pattern: aborting due to `-Z treat-err-as-bug=1`
 // error-pattern: [trigger_delay_span_bug] triggering a delay span bug
 // normalize-stderr-test "note: .*\n\n" -> ""
-// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
 // rustc-env:RUST_BACKTRACE=0
 
 #![feature(rustc_attrs)]
diff --git a/tests/ui/treat-err-as-bug/err.rs b/tests/ui/treat-err-as-bug/err.rs
index de3e9ed6cf9..4090a706f99 100644
--- a/tests/ui/treat-err-as-bug/err.rs
+++ b/tests/ui/treat-err-as-bug/err.rs
@@ -3,7 +3,7 @@
 // error-pattern: aborting due to `-Z treat-err-as-bug=1`
 // error-pattern: [eval_to_allocation_raw] const-evaluating + checking `C`
 // normalize-stderr-test "note: .*\n\n" -> ""
-// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
 // rustc-env:RUST_BACKTRACE=0
 
 #![crate_type = "rlib"]