about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap6
-rw-r--r--Cargo.lock6
-rw-r--r--compiler/rustc_ast/src/ast.rs10
-rw-r--r--compiler/rustc_ast_ir/src/lib.rs8
-rw-r--r--compiler/rustc_ast_passes/messages.ftl1
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs6
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs6
-rw-r--r--compiler/rustc_borrowck/messages.ftl6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs534
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs97
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs22
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs89
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs145
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/.cirrus.yml5
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js4
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml3
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch13
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh12
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs25
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs21
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs125
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs87
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs93
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs25
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs42
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs95
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs20
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs38
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml6
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0384.md13
-rw-r--r--compiler/rustc_errors/src/emitter.rs9
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs73
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs98
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs29
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs45
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs46
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs122
-rw-r--r--compiler/rustc_infer/messages.ftl3
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs75
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs24
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs7
-rw-r--r--compiler/rustc_middle/src/query/keys.rs13
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs12
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs67
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/util/common.rs45
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs78
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs20
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs3
-rw-r--r--compiler/rustc_query_impl/src/lib.rs5
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs12
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs7
-rw-r--r--compiler/rustc_resolve/src/imports.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs45
-rw-r--r--compiler/rustc_serialize/src/int_overflow.rs65
-rw-r--r--compiler/rustc_serialize/src/leb128.rs14
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/src/opaque.rs10
-rw-r--r--compiler/rustc_session/src/config.rs44
-rw-r--r--compiler/rustc_session/src/filesearch.rs5
-rw-r--r--compiler/rustc_session/src/options.rs20
-rw-r--r--compiler/rustc_span/src/lib.rs39
-rw-r--r--compiler/rustc_span/src/source_map.rs14
-rw-r--r--compiler/rustc_span/src/span_encoding.rs8
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs56
-rw-r--r--compiler/rustc_target/src/asm/mod.rs22
-rw-r--r--compiler/rustc_target/src/spec/mod.rs74
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs17
-rw-r--r--config.example.toml4
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/raw_vec.rs11
-rw-r--r--library/alloc/src/rc.rs5
-rw-r--r--library/alloc/src/sync.rs10
-rw-r--r--library/alloc/src/vec/in_place_collect.rs21
-rw-r--r--library/alloc/src/vec/in_place_drop.rs7
-rw-r--r--library/alloc/src/vec/into_iter.rs2
-rw-r--r--library/alloc/src/vec/mod.rs27
-rw-r--r--library/alloc/src/vec/spec_from_iter.rs2
m---------library/backtrace0
-rw-r--r--library/core/src/clone.rs5
-rw-r--r--library/core/src/cmp.rs10
-rw-r--r--library/core/src/convert/num.rs7
-rw-r--r--library/core/src/ffi/c_str.rs4
-rw-r--r--library/core/src/fmt/float.rs16
-rw-r--r--library/core/src/fmt/mod.rs22
-rw-r--r--library/core/src/fmt/nofloat.rs2
-rw-r--r--library/core/src/fmt/rt.rs84
-rw-r--r--library/core/src/io/borrowed_buf.rs5
-rw-r--r--library/core/src/iter/traits/collect.rs33
-rw-r--r--library/core/src/lib.rs10
-rw-r--r--library/core/src/marker.rs8
-rw-r--r--library/core/src/net/socket_addr.rs4
-rw-r--r--library/core/src/num/f128.rs120
-rw-r--r--library/core/src/num/f16.rs120
-rw-r--r--library/core/src/ops/arith.rs22
-rw-r--r--library/core/src/pin.rs12
-rw-r--r--library/core/src/primitive_docs.rs30
-rw-r--r--library/core/src/ptr/const_ptr.rs14
-rw-r--r--library/core/src/ptr/mut_ptr.rs11
-rw-r--r--library/core/src/ptr/non_null.rs9
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/panic_unwind/src/lib.rs2
-rw-r--r--library/panic_unwind/src/seh.rs112
-rw-r--r--library/proc_macro/src/bridge/client.rs6
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/std/src/f128.rs11
-rw-r--r--library/std/src/f128/tests.rs40
-rw-r--r--library/std/src/f16.rs11
-rw-r--r--library/std/src/f16/tests.rs46
-rw-r--r--library/std/src/fs.rs14
-rw-r--r--library/std/src/io/buffered/bufreader.rs7
-rw-r--r--library/std/src/io/error.rs24
-rw-r--r--library/std/src/io/impls.rs28
-rw-r--r--library/std/src/io/mod.rs34
-rw-r--r--library/std/src/io/stdio.rs24
-rw-r--r--library/std/src/io/tests.rs9
-rw-r--r--library/std/src/lib.rs18
-rw-r--r--library/std/src/os/fd/owned.rs5
-rw-r--r--library/std/src/os/unix/fs.rs11
-rw-r--r--library/std/src/os/unix/net/addr.rs10
-rw-r--r--library/std/src/os/wasi/fs.rs11
-rw-r--r--library/std/src/panicking.rs8
-rw-r--r--library/std/src/path.rs11
-rw-r--r--library/std/src/sys/pal/hermit/net.rs10
-rw-r--r--library/std/src/sys/pal/sgx/net.rs15
-rw-r--r--library/std/src/sys/pal/solid/mod.rs5
-rw-r--r--library/std/src/sys/pal/solid/net.rs10
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs5
-rw-r--r--library/std/src/sys/pal/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/net.rs10
-rw-r--r--library/std/src/sys/pal/unix/thread.rs10
-rw-r--r--library/std/src/sys/pal/unsupported/common.rs5
-rw-r--r--library/std/src/sys/pal/windows/net.rs10
-rw-r--r--library/std/src/sys/pal/windows/thread.rs31
-rw-r--r--library/std/src/sys/pal/xous/net/tcpstream.rs10
-rw-r--r--library/std/src/sys/pal/xous/net/udp.rs10
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs7
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/sys_common/net.rs4
-rw-r--r--library/std/src/sys_common/thread.rs18
-rw-r--r--library/std/src/thread/local.rs60
-rw-r--r--library/std/src/thread/mod.rs27
-rw-r--r--library/std/src/thread/scoped.rs10
m---------library/stdarch0
-rwxr-xr-xsrc/bootstrap/configure.py4
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs107
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs15
-rw-r--r--src/ci/docker/host-x86_64/dist-various-1/Dockerfile3
-rw-r--r--src/doc/unstable-book/src/compiler-flags/linker-features.md35
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md32
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs22
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/librustdoc/formats/cache.rs10
-rw-r--r--src/librustdoc/html/templates/page.html3
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr2
-rw-r--r--src/tools/clippy/tests/ui/empty_docs.stderr11
-rw-r--r--src/tools/compiletest/src/header.rs43
-rw-r--r--src/tools/compiletest/src/header/tests.rs21
-rw-r--r--src/tools/compiletest/src/runtest.rs29
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs9
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs80
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs176
-rw-r--r--src/tools/run-make-support/src/cc.rs39
-rw-r--r--src/tools/run-make-support/src/lib.rs153
-rw-r--r--src/tools/run-make-support/src/run.rs4
-rw-r--r--src/tools/run-make-support/src/rustc.rs64
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs30
-rw-r--r--src/tools/tidy/Cargo.toml1
-rw-r--r--src/tools/tidy/src/deps.rs40
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/assembly/asm/aarch64-types.rs155
-rw-r--r--tests/codegen/ascii-char.rs2
-rw-r--r--tests/codegen/cffi/c-variadic-naked.rs19
-rw-r--r--tests/codegen/float/f128.rs129
-rw-r--r--tests/codegen/float/f16.rs129
-rw-r--r--tests/codegen/naked-fn/naked-functions.rs2
-rw-r--r--tests/codegen/unchecked_shifts.rs8
-rw-r--r--tests/run-make/compiler-builtins/rmake.rs11
-rw-r--r--tests/run-make/rust-lld/Makefile6
-rw-r--r--tests/rustdoc-ui/auxiliary/include-str-bare-urls.md10
-rw-r--r--tests/rustdoc-ui/include-str-bare-urls.rs15
-rw-r--r--tests/rustdoc-ui/include-str-bare-urls.stderr15
-rw-r--r--tests/rustdoc-ui/intra-doc/warning.rs4
-rw-r--r--tests/rustdoc-ui/intra-doc/warning.stderr19
-rw-r--r--tests/rustdoc-ui/invalid-syntax.stderr7
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.stderr24
-rw-r--r--tests/rustdoc/inline_cross/inline_hidden.rs14
-rw-r--r--tests/ui/array-slice-vec/vector-no-ann.stderr2
-rw-r--r--tests/ui/asm/aarch64/type-check-2-2.stderr8
-rw-r--r--tests/ui/asm/x86_64/type-check-5.stderr8
-rw-r--r--tests/ui/associated-types/associated-types-outlives.rs4
-rw-r--r--tests/ui/associated-types/associated-types-outlives.stderr5
-rw-r--r--tests/ui/associated-types/issue-25700.stderr6
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.rs1
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.stderr11
-rw-r--r--tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs23
-rw-r--r--tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr20
-rw-r--r--tests/ui/async-await/async-closures/moro-example.rs43
-rw-r--r--tests/ui/async-await/async-closures/no-borrow-from-env.rs44
-rw-r--r--tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs47
-rw-r--r--tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr152
-rw-r--r--tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs17
-rw-r--r--tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr46
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.afn.stderr4
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr4
-rw-r--r--tests/ui/augmented-assignments.rs2
-rw-r--r--tests/ui/augmented-assignments.stderr9
-rw-r--r--tests/ui/binop/issue-77910-1.stderr4
-rw-r--r--tests/ui/binop/issue-77910-2.stderr4
-rw-r--r--tests/ui/binop/multiply-is-deref-on-rhs.rs8
-rw-r--r--tests/ui/binop/multiply-is-deref-on-rhs.stderr16
-rw-r--r--tests/ui/borrowck/argument_number_mismatch_ice.stderr5
-rw-r--r--tests/ui/borrowck/borrow-tuple-fields.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-block-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit-2.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-closures-slice-patterns.stderr11
-rw-r--r--tests/ui/borrowck/borrowck-field-sensitivity.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-a.rs1
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-a.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-in-static.rs2
-rw-r--r--tests/ui/borrowck/borrowck-in-static.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fn-expr.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fru.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-op-equal.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-plus-equal.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-2.fixed2
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-2.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-issue-48962.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed2
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-static-item.rs3
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-static-item.stderr8
-rw-r--r--tests/ui/borrowck/borrowck-move-subcomponent.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-multiple-captures.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-call.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-return.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-storage-dead.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-struct-update-with-dtor.rs61
-rw-r--r--tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr198
-rw-r--r--tests/ui/borrowck/borrowck-unary-move.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-unboxed-closures.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-uninit-after-item.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-uninit-in-assignop.stderr40
-rw-r--r--tests/ui/borrowck/borrowck-uninit-ref-chain.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed11
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr8
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed12
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed10
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.rs3
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr20
-rw-r--r--tests/ui/borrowck/clone-on-ref.stderr5
-rw-r--r--tests/ui/borrowck/clone-span-on-try-operator.fixed2
-rw-r--r--tests/ui/borrowck/clone-span-on-try-operator.stderr5
-rw-r--r--tests/ui/borrowck/issue-101119.stderr14
-rw-r--r--tests/ui/borrowck/issue-103250.stderr4
-rw-r--r--tests/ui/borrowck/issue-103624.stderr6
-rw-r--r--tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr5
-rw-r--r--tests/ui/borrowck/issue-17718-static-move.stderr5
-rw-r--r--tests/ui/borrowck/issue-20801.stderr20
-rw-r--r--tests/ui/borrowck/issue-24267-flow-exit.stderr8
-rw-r--r--tests/ui/borrowck/issue-62107-match-arm-scopes.stderr4
-rw-r--r--tests/ui/borrowck/issue-64453.stderr5
-rw-r--r--tests/ui/borrowck/issue-87456-point-to-closure.stderr4
-rw-r--r--tests/ui/borrowck/move-error-in-promoted-2.stderr6
-rw-r--r--tests/ui/borrowck/move-error-in-promoted.stderr5
-rw-r--r--tests/ui/borrowck/move-error-snippets.stderr5
-rw-r--r--tests/ui/borrowck/move-from-union-field-issue-66500.stderr24
-rw-r--r--tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr12
-rw-r--r--tests/ui/borrowck/suggest-assign-rvalue.stderr22
-rw-r--r--tests/ui/borrowck/trait-impl-argument-difference-ice.rs25
-rw-r--r--tests/ui/borrowck/trait-impl-argument-difference-ice.stderr60
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed2
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr4
-rw-r--r--tests/ui/box/leak-alloc.stderr6
-rw-r--r--tests/ui/btreemap/btreemap_dropck.stderr6
-rw-r--r--tests/ui/check-static-values-constraints.stderr4
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr4
-rw-r--r--tests/ui/closures/return-value-lifetime-error.fixed16
-rw-r--r--tests/ui/closures/return-value-lifetime-error.rs16
-rw-r--r--tests/ui/closures/return-value-lifetime-error.stderr16
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.fixed6
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.rs3
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.stderr6
-rw-r--r--tests/ui/const-generics/defaults/doesnt_infer.rs2
-rw-r--r--tests/ui/const-generics/defaults/doesnt_infer.stderr2
-rw-r--r--tests/ui/const-generics/generic_arg_infer/issue-91614.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr2
-rw-r--r--tests/ui/consts/const_fn_unsize.rs1
-rw-r--r--tests/ui/consts/issue-78655.stderr4
-rw-r--r--tests/ui/derives/deriving-with-repr-packed-move-errors.stderr96
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.stderr5
-rw-r--r--tests/ui/drop/repeat-drop-2.stderr4
-rw-r--r--tests/ui/dropck/drop-with-active-borrows-1.stderr5
-rw-r--r--tests/ui/error-codes/E0449.fixed18
-rw-r--r--tests/ui/error-codes/E0449.rs4
-rw-r--r--tests/ui/error-codes/E0449.stderr12
-rw-r--r--tests/ui/error-codes/E0504.stderr6
-rw-r--r--tests/ui/error-codes/E0505.stderr6
-rw-r--r--tests/ui/error-codes/E0507.stderr5
-rw-r--r--tests/ui/error-codes/E0508-fail.stderr5
-rw-r--r--tests/ui/error-codes/E0508.stderr5
-rw-r--r--tests/ui/error-codes/E0509.stderr5
-rw-r--r--tests/ui/fmt/send-sync.stderr4
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr6
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr6
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type.stderr6
-rw-r--r--tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr5
-rw-r--r--tests/ui/generic-const-items/inference-failure.stderr2
-rw-r--r--tests/ui/generic-const-items/parameter-defaults.stderr2
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr4
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr8
-rw-r--r--tests/ui/imports/redundant-import-extern-prelude.rs16
-rw-r--r--tests/ui/imports/redundant-import-issue-121915-2015.rs3
-rw-r--r--tests/ui/imports/redundant-import-issue-121915-2015.stderr17
-rw-r--r--tests/ui/imports/redundant-import-issue-121915.rs9
-rw-r--r--tests/ui/imports/redundant-import-issue-121915.stderr14
-rw-r--r--tests/ui/imports/redundant-import-lang-prelude-attr.rs17
-rw-r--r--tests/ui/imports/redundant-import-lang-prelude.rs17
-rw-r--r--tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs23
-rw-r--r--tests/ui/imports/suggest-remove-issue-121315.rs9
-rw-r--r--tests/ui/imports/suggest-remove-issue-121315.stderr50
-rw-r--r--tests/ui/include-macros/mismatched-types.stderr7
-rw-r--r--tests/ui/inference/cannot-infer-closure-circular.rs2
-rw-r--r--tests/ui/inference/cannot-infer-closure-circular.stderr2
-rw-r--r--tests/ui/inference/erase-type-params-in-label.stderr4
-rw-r--r--tests/ui/inference/issue-104649.stderr2
-rw-r--r--tests/ui/inference/issue-72690.stderr2
-rw-r--r--tests/ui/inference/issue-83606.rs2
-rw-r--r--tests/ui/inference/issue-83606.stderr2
-rw-r--r--tests/ui/inference/untyped-primitives.rs9
-rw-r--r--tests/ui/issues/issue-11771.stderr12
-rw-r--r--tests/ui/issues/issue-12187-1.stderr2
-rw-r--r--tests/ui/issues/issue-12187-2.stderr2
-rw-r--r--tests/ui/issues/issue-17385.stderr12
-rw-r--r--tests/ui/issues/issue-17551.stderr2
-rw-r--r--tests/ui/issues/issue-21596.rs5
-rw-r--r--tests/ui/issues/issue-21596.stderr15
-rw-r--r--tests/ui/issues/issue-23046.stderr2
-rw-r--r--tests/ui/issues/issue-24357.rs2
-rw-r--r--tests/ui/issues/issue-24357.stderr6
-rw-r--r--tests/ui/issues/issue-2590.stderr5
-rw-r--r--tests/ui/issues/issue-27042.stderr2
-rw-r--r--tests/ui/issues/issue-28433.stderr4
-rw-r--r--tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr4
-rw-r--r--tests/ui/issues/issue-50582.stderr6
-rw-r--r--tests/ui/issues/issue-52262.stderr6
-rw-r--r--tests/ui/issues/issue-98299.stderr2
-rw-r--r--tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs8
-rw-r--r--tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr13
-rw-r--r--tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs9
-rw-r--r--tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rs3
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-4.rs9
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr26
-rw-r--r--tests/ui/linkage-attr/uikit-framework.rs25
-rw-r--r--tests/ui/lint/unused/issue-59896.rs3
-rw-r--r--tests/ui/lint/unused/issue-59896.stderr17
-rw-r--r--tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs39
-rw-r--r--tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr40
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob-parent.rs2
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr17
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob.rs2
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob.stderr16
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-issue-71450.rs3
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr17
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs12
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr44
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs6
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr26
-rw-r--r--tests/ui/lint/use-redundant/use-redundant.rs2
-rw-r--r--tests/ui/lint/use-redundant/use-redundant.stderr11
-rw-r--r--tests/ui/loops/loop-break-value.rs4
-rw-r--r--tests/ui/loops/loop-break-value.stderr77
-rw-r--r--tests/ui/loops/loop-labeled-break-value.stderr6
-rw-r--r--tests/ui/loops/loop-proper-liveness.stderr4
-rw-r--r--tests/ui/loops/loop-properly-diverging-2.stderr2
-rw-r--r--tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr2
-rw-r--r--tests/ui/methods/suggest-convert-ptr-to-ref.rs17
-rw-r--r--tests/ui/methods/suggest-convert-ptr-to-ref.stderr70
-rw-r--r--tests/ui/mir/issue-102389.stderr6
-rw-r--r--tests/ui/mismatched_types/binops.stderr18
-rw-r--r--tests/ui/moves/issue-72649-uninit-in-loop.rs4
-rw-r--r--tests/ui/moves/issue-72649-uninit-in-loop.stderr44
-rw-r--r--tests/ui/moves/issue-75904-move-closure-loop.stderr7
-rw-r--r--tests/ui/moves/move-fn-self-receiver.stderr11
-rw-r--r--tests/ui/moves/move-into-dead-array-1.stderr4
-rw-r--r--tests/ui/moves/move-of-addr-of-mut.stderr4
-rw-r--r--tests/ui/moves/move-out-of-array-1.stderr6
-rw-r--r--tests/ui/moves/moves-based-on-type-capture-clause-bad.rs2
-rw-r--r--tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr4
-rw-r--r--tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr5
-rw-r--r--tests/ui/moves/needs-clone-through-deref.fixed2
-rw-r--r--tests/ui/moves/needs-clone-through-deref.stderr4
-rw-r--r--tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed2
-rw-r--r--tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr4
-rw-r--r--tests/ui/moves/suggest-clone.fixed2
-rw-r--r--tests/ui/moves/suggest-clone.stderr4
-rw-r--r--tests/ui/never_type/issue-52443.stderr2
-rw-r--r--tests/ui/nll/cannot-move-block-spans.stderr42
-rw-r--r--tests/ui/nll/closure-access-spans.stderr16
-rw-r--r--tests/ui/nll/closure-move-spans.fixed23
-rw-r--r--tests/ui/nll/closure-move-spans.rs2
-rw-r--r--tests/ui/nll/closure-move-spans.stderr21
-rw-r--r--tests/ui/nll/closures-in-loops.stderr6
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-use.stderr12
-rw-r--r--tests/ui/nll/issue-27282-move-match-input-into-guard.stderr10
-rw-r--r--tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr4
-rw-r--r--tests/ui/nll/issue-52086.stderr10
-rw-r--r--tests/ui/nll/issue-52663-span-decl-captured-variable.stderr5
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.stderr8
-rw-r--r--tests/ui/nll/match-on-borrowed.stderr4
-rw-r--r--tests/ui/nll/move-errors.stderr31
-rw-r--r--tests/ui/once-cant-call-twice-on-heap.stderr12
-rw-r--r--tests/ui/parser/assoc/assoc-static-semantic-fail.stderr4
-rw-r--r--tests/ui/parser/default.stderr2
-rw-r--r--tests/ui/parser/recover/recover-range-pats.stderr36
-rw-r--r--tests/ui/parser/trait-pub-assoc-const.stderr2
-rw-r--r--tests/ui/parser/trait-pub-assoc-ty.stderr2
-rw-r--r--tests/ui/parser/trait-pub-method.stderr2
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr10
-rw-r--r--tests/ui/precondition-checks/cfg-ub-checks-default.rs2
-rw-r--r--tests/ui/privacy/issue-113860-1.stderr2
-rw-r--r--tests/ui/privacy/issue-113860-2.stderr2
-rw-r--r--tests/ui/privacy/issue-113860.stderr2
-rw-r--r--tests/ui/privacy/issue-29161.stderr2
-rw-r--r--tests/ui/privacy/priv-in-bad-locations.stderr8
-rw-r--r--tests/ui/privacy/privacy-sanity.stderr36
-rw-r--r--tests/ui/privacy/useless-pub.stderr6
-rw-r--r--tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr8
-rw-r--r--tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr8
-rw-r--r--tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr10
-rw-r--r--tests/ui/span/send-is-not-static-std-sync.stderr18
-rw-r--r--tests/ui/suggestions/borrow-for-loop-head.stderr6
-rw-r--r--tests/ui/suggestions/deref-path-method.stderr2
-rw-r--r--tests/ui/suggestions/for-i-in-vec.fixed6
-rw-r--r--tests/ui/suggestions/for-i-in-vec.stderr13
-rw-r--r--tests/ui/suggestions/issue-68049-1.stderr2
-rw-r--r--tests/ui/suggestions/issue-68049-2.rs6
-rw-r--r--tests/ui/suggestions/issue-68049-2.stderr14
-rw-r--r--tests/ui/suggestions/option-content-move.fixed4
-rw-r--r--tests/ui/suggestions/option-content-move.stderr8
-rw-r--r--tests/ui/suggestions/return-closures.stderr2
-rw-r--r--tests/ui/traits/copy-guessing.rs2
-rw-r--r--tests/ui/traits/copy-guessing.stderr2
-rw-r--r--tests/ui/traits/issue-77982.stderr4
-rw-r--r--tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr6
-rw-r--r--tests/ui/try-block/try-block-bad-lifetime.stderr5
-rw-r--r--tests/ui/type-inference/or_else-multiple-type-params.stderr2
-rw-r--r--tests/ui/type/type-error-break-tail.stderr2
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed37
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs18
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr12
-rw-r--r--tests/ui/typeck/question-mark-operator-suggestion-span.rs22
-rw-r--r--tests/ui/typeck/question-mark-operator-suggestion-span.stderr31
-rw-r--r--tests/ui/typeck/return_type_containing_closure.rs2
-rw-r--r--tests/ui/typeck/return_type_containing_closure.stderr6
-rw-r--r--tests/ui/ufcs/bad-builder.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr2
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.fixed31
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.rs2
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.stderr4
-rw-r--r--tests/ui/union/union-borrow-move-parent-sibling.stderr5
-rw-r--r--tests/ui/union/union-move.stderr15
-rw-r--r--tests/ui/variance/variance-issue-20533.rs19
-rw-r--r--tests/ui/variance/variance-issue-20533.stderr61
530 files changed, 6734 insertions, 2655 deletions
diff --git a/.mailmap b/.mailmap
index 93f5ca8157c..0bd16a797ca 100644
--- a/.mailmap
+++ b/.mailmap
@@ -307,6 +307,8 @@ Joseph T. Lyons <JosephTLyons@gmail.com> <JosephTLyons@users.noreply.github.com>
 Josh Cotton <jcotton42@outlook.com>
 Josh Driver <keeperofdakeys@gmail.com>
 Josh Holmer <jholmer.in@gmail.com>
+Josh Stone <cuviper@gmail.com> <jistone@redhat.com>
+Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org>
 Julian Knodt <julianknodt@gmail.com>
 jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com>
 Junyoung Cho <june0.cho@samsung.com>
@@ -474,7 +476,8 @@ Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
 phosphorus <steepout@qq.com>
 Pierre Krieger <pierre.krieger1708@gmail.com>
 pierwill <pierwill@users.noreply.github.com> <19642016+pierwill@users.noreply.github.com>
-Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io> <pietro.albini@ferrous-systems.com>
+Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io>
+Pietro Albini <pietro@pietroalbini.org> <pietro.albini@ferrous-systems.com>
 Pradyumna Rahul <prkinformed@gmail.com>
 Przemysław Wesołek <jest@go.art.pl> Przemek Wesołek <jest@go.art.pl>
 r00ster <r00ster91@protonmail.com>
@@ -543,6 +546,7 @@ Takashi Idobe <idobetakashi@gmail.com>
 Takayuki Maeda <takoyaki0316@gmail.com>
 Tamir Duberstein <tamird@gmail.com> Tamir Duberstein <tamird@squareup.com>
 Tatsuyuki Ishi <ishitatsuyuki@gmail.com>
+Tau Gärtli <git@tau.garden> <ruben.schmidmeister@icloud.com>
 Tero Hänninen <lgvz@users.noreply.github.com> Tero Hänninen <tejohann@kapsi.fi>
 The8472 <git@infinite-source.de>
 Theo Belaire <theo.belaire@gmail.com> Theo Belaire <tyr.god.of.war.42@gmail.com>
diff --git a/Cargo.lock b/Cargo.lock
index b1bdaef81ff..c211024e1ac 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -469,9 +469,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
 
 [[package]]
 name = "cfg-if"
@@ -4263,7 +4263,6 @@ dependencies = [
  "either",
  "field-offset",
  "gsgdt",
- "measureme",
  "polonius-engine",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -5580,7 +5579,6 @@ dependencies = [
 name = "tidy"
 version = "0.1.0"
 dependencies = [
- "cargo-platform",
  "cargo_metadata 0.15.4",
  "ignore",
  "lazy_static",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 63ce6685e43..5b708cf4e1a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -920,14 +920,8 @@ impl BinOpKind {
         matches!(self, BinOpKind::And | BinOpKind::Or)
     }
 
-    pub fn is_comparison(&self) -> bool {
-        use BinOpKind::*;
-        // Note for developers: please keep this match exhaustive;
-        // we want compilation to fail if another variant is added.
-        match *self {
-            Eq | Lt | Le | Ne | Gt | Ge => true,
-            And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false,
-        }
+    pub fn is_comparison(self) -> bool {
+        crate::util::parser::AssocOp::from_ast_binop(self).is_comparison()
     }
 
     /// Returns `true` if the binary operator takes its arguments by value.
diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs
index ff7a1552047..9ff2e32f06b 100644
--- a/compiler/rustc_ast_ir/src/lib.rs
+++ b/compiler/rustc_ast_ir/src/lib.rs
@@ -51,6 +51,14 @@ impl Mutability {
         }
     }
 
+    /// Returns `"const"` or `"mut"` depending on the mutability.
+    pub fn ptr_str(self) -> &'static str {
+        match self {
+            Mutability::Not => "const",
+            Mutability::Mut => "mut",
+        }
+    }
+
     /// Returns `""` (empty string) or `"mutably "` depending on the mutability.
     pub fn mutably_str(self) -> &'static str {
         match self {
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index ac3799e7a05..a3731e94276 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -273,6 +273,7 @@ ast_passes_visibility_not_permitted =
     .trait_impl = trait items always share the visibility of their trait
     .individual_impl_items = place qualifiers on individual impl items instead
     .individual_foreign_items = place qualifiers on individual foreign items instead
+    .remove_qualifier_sugg = remove the qualifier
 
 ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
     .note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 01addc8127e..cb4dcf3ae75 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -266,7 +266,11 @@ impl<'a> AstValidator<'a> {
             return;
         }
 
-        self.dcx().emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
+        self.dcx().emit_err(errors::VisibilityNotPermitted {
+            span: vis.span,
+            note,
+            remove_qualifier_sugg: vis.span,
+        });
     }
 
     fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 8ae9f7d3966..f397c949e04 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -31,6 +31,12 @@ pub struct VisibilityNotPermitted {
     pub span: Span,
     #[subdiagnostic]
     pub note: VisibilityNotPermittedNote,
+    #[suggestion(
+        ast_passes_remove_qualifier_sugg,
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    pub remove_qualifier_sugg: Span,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index 587536e1f9a..c14a617eb91 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -87,6 +87,12 @@ borrowck_move_unsized =
 borrowck_moved_a_fn_once_in_call =
     this value implements `FnOnce`, which causes it to be moved when called
 
+borrowck_moved_a_fn_once_in_call_call =
+    `FnOnce` closures can only be called once
+
+borrowck_moved_a_fn_once_in_call_def =
+    `{$ty}` is made to be an `FnOnce` closure here
+
 borrowck_moved_due_to_await =
     {$place_name} {$is_partial ->
         [true] partially moved
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 62e16d445c6..48cd9c268a1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -203,13 +203,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                 if !seen_spans.contains(&move_span) {
                     if !closure {
-                        self.suggest_ref_or_clone(
-                            mpi,
-                            move_span,
-                            &mut err,
-                            &mut in_pattern,
-                            move_spans,
-                        );
+                        self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans);
                     }
 
                     let msg_opt = CapturedMessageOpt {
@@ -283,7 +277,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 Some(name) => format!("`{name}`"),
                 None => "value".to_owned(),
             };
-            if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
+            if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg)
+                || if let UseSpans::FnSelfUse { kind, .. } = use_spans
+                    && let CallKind::FnCall { fn_trait_id, self_ty } = kind
+                    && let ty::Param(_) = self_ty.kind()
+                    && ty == self_ty
+                    && Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait()
+                {
+                    // this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
+                    true
+                } else {
+                    false
+                }
+            {
                 // Suppress the next suggestion since we don't want to put more bounds onto
                 // something that already has `Fn`-like bounds (or is a closure), so we can't
                 // restrict anyways.
@@ -339,18 +345,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn suggest_ref_or_clone(
         &self,
         mpi: MovePathIndex,
-        move_span: Span,
         err: &mut Diag<'tcx>,
         in_pattern: &mut bool,
         move_spans: UseSpans<'_>,
     ) {
+        let move_span = match move_spans {
+            UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
+            _ => move_spans.args_or_use(),
+        };
         struct ExpressionFinder<'hir> {
             expr_span: Span,
             expr: Option<&'hir hir::Expr<'hir>>,
             pat: Option<&'hir hir::Pat<'hir>>,
             parent_pat: Option<&'hir hir::Pat<'hir>>,
+            hir: rustc_middle::hir::map::Map<'hir>,
         }
         impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+            type NestedFilter = OnlyBodies;
+
+            fn nested_visit_map(&mut self) -> Self::Map {
+                self.hir
+            }
+
             fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
                 if e.span == self.expr_span {
                     self.expr = Some(e);
@@ -385,8 +401,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let expr = hir.body(body_id).value;
             let place = &self.move_data.move_paths[mpi].place;
             let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);
-            let mut finder =
-                ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
+            let mut finder = ExpressionFinder {
+                expr_span: move_span,
+                expr: None,
+                pat: None,
+                parent_pat: None,
+                hir,
+            };
             finder.visit_expr(expr);
             if let Some(span) = span
                 && let Some(expr) = finder.expr
@@ -467,16 +488,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 } else if let UseSpans::ClosureUse {
                     closure_kind:
                         ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
-                    args_span: _,
-                    capture_kind_span: _,
-                    path_span,
+                    ..
                 } = move_spans
                 {
-                    self.suggest_cloning(err, ty, expr, path_span);
+                    self.suggest_cloning(err, ty, expr, None);
                 } else if self.suggest_hoisting_call_outside_loop(err, expr) {
                     // The place where the the type moves would be misleading to suggest clone.
                     // #121466
-                    self.suggest_cloning(err, ty, expr, move_span);
+                    self.suggest_cloning(err, ty, expr, None);
                 }
             }
             if let Some(pat) = finder.pat {
@@ -652,6 +671,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err
     }
 
+    fn ty_kind_suggestion(&self, ty: Ty<'tcx>) -> Option<String> {
+        // Keep in sync with `rustc_hir_analysis/src/check/mod.rs:ty_kind_suggestion`.
+        // FIXME: deduplicate the above.
+        let tcx = self.infcx.tcx;
+        let implements_default = |ty| {
+            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+                return false;
+            };
+            self.infcx
+                .type_implements_trait(default_trait, [ty], self.param_env)
+                .must_apply_modulo_regions()
+        };
+
+        Some(match ty.kind() {
+            ty::Never | ty::Error(_) => return None,
+            ty::Bool => "false".to_string(),
+            ty::Char => "\'x\'".to_string(),
+            ty::Int(_) | ty::Uint(_) => "42".into(),
+            ty::Float(_) => "3.14159".into(),
+            ty::Slice(_) => "[]".to_string(),
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
+                "vec![]".to_string()
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
+                "String::new()".to_string()
+            }
+            ty::Adt(def, args) if def.is_box() => {
+                format!("Box::new({})", self.ty_kind_suggestion(args[0].expect_ty())?)
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
+                "None".to_string()
+            }
+            ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
+                format!("Ok({})", self.ty_kind_suggestion(args[0].expect_ty())?)
+            }
+            ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
+            ty::Ref(_, ty, mutability) => {
+                if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
+                    "\"\"".to_string()
+                } else {
+                    let Some(ty) = self.ty_kind_suggestion(*ty) else {
+                        return None;
+                    };
+                    format!("&{}{ty}", mutability.prefix_str())
+                }
+            }
+            ty::Array(ty, len) => format!(
+                "[{}; {}]",
+                self.ty_kind_suggestion(*ty)?,
+                len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
+            ),
+            ty::Tuple(tys) => format!(
+                "({})",
+                tys.iter()
+                    .map(|ty| self.ty_kind_suggestion(ty))
+                    .collect::<Option<Vec<String>>>()?
+                    .join(", ")
+            ),
+            _ => "value".to_string(),
+        })
+    }
+
     fn suggest_assign_value(
         &self,
         err: &mut Diag<'_>,
@@ -661,34 +742,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
         debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
 
-        let tcx = self.infcx.tcx;
-        let implements_default = |ty, param_env| {
-            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
-                return false;
-            };
-            self.infcx
-                .type_implements_trait(default_trait, [ty], param_env)
-                .must_apply_modulo_regions()
-        };
-
-        let assign_value = match ty.kind() {
-            ty::Bool => "false",
-            ty::Float(_) => "0.0",
-            ty::Int(_) | ty::Uint(_) => "0",
-            ty::Never | ty::Error(_) => "",
-            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
-            ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
-            _ => "todo!()",
+        let Some(assign_value) = self.ty_kind_suggestion(ty) else {
+            return;
         };
 
-        if !assign_value.is_empty() {
-            err.span_suggestion_verbose(
-                sugg_span.shrink_to_hi(),
-                "consider assigning a value",
-                format!(" = {assign_value}"),
-                Applicability::MaybeIncorrect,
-            );
-        }
+        err.span_suggestion_verbose(
+            sugg_span.shrink_to_hi(),
+            "consider assigning a value",
+            format!(" = {assign_value}"),
+            Applicability::MaybeIncorrect,
+        );
     }
 
     fn suggest_borrow_fn_like(
@@ -916,7 +979,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         sm.span_to_diagnostic_string(span)
                     }
                 };
-                let mut spans: MultiSpan = spans.clone().into();
+                let mut spans: MultiSpan = spans.into();
                 // Point at all the `continue`s and explicit `break`s in the relevant loops.
                 for (desc, elements) in [
                     ("`break` exits", &finder.found_breaks),
@@ -987,8 +1050,272 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         can_suggest_clone
     }
 
-    fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
+    /// We have `S { foo: val, ..base }`, and we suggest instead writing
+    /// `S { foo: val, bar: base.bar.clone(), .. }` when valid.
+    fn suggest_cloning_on_functional_record_update(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        expr: &'cx hir::Expr<'cx>,
+    ) {
+        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+        let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return };
+        let hir::QPath::Resolved(_, path) = struct_qpath else { return };
+        let hir::def::Res::Def(_, def_id) = path.res else { return };
+        let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return };
+        let ty::Adt(def, args) = expr_ty.kind() else { return };
+        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = base.kind else { return };
+        let (hir::def::Res::Local(_)
+        | hir::def::Res::Def(
+            DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } | DefKind::AssocConst,
+            _,
+        )) = path.res
+        else {
+            return;
+        };
+        let Ok(base_str) = self.infcx.tcx.sess.source_map().span_to_snippet(base.span) else {
+            return;
+        };
+
+        // 1. look for the fields of type `ty`.
+        // 2. check if they are clone and add them to suggestion
+        // 3. check if there are any values left to `..` and remove it if not
+        // 4. emit suggestion to clone the field directly as `bar: base.bar.clone()`
+
+        let mut final_field_count = fields.len();
+        let Some(variant) = def.variants().iter().find(|variant| variant.def_id == def_id) else {
+            // When we have an enum, look for the variant that corresponds to the variant the user
+            // wrote.
+            return;
+        };
+        let mut sugg = vec![];
+        for field in &variant.fields {
+            // In practice unless there are more than one field with the same type, we'll be
+            // suggesting a single field at a type, because we don't aggregate multiple borrow
+            // checker errors involving the functional record update sytnax into a single one.
+            let field_ty = field.ty(self.infcx.tcx, args);
+            let ident = field.ident(self.infcx.tcx);
+            if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) {
+                // Suggest adding field and cloning it.
+                sugg.push(format!("{ident}: {base_str}.{ident}.clone()"));
+                final_field_count += 1;
+            }
+        }
+        let (span, sugg) = match fields {
+            [.., last] => (
+                if final_field_count == variant.fields.len() {
+                    // We'll remove the `..base` as there aren't any fields left.
+                    last.span.shrink_to_hi().with_hi(base.span.hi())
+                } else {
+                    last.span.shrink_to_hi()
+                },
+                format!(", {}", sugg.join(", ")),
+            ),
+            // Account for no fields in suggestion span.
+            [] => (
+                expr.span.with_lo(struct_qpath.span().hi()),
+                if final_field_count == variant.fields.len() {
+                    // We'll remove the `..base` as there aren't any fields left.
+                    format!(" {{ {} }}", sugg.join(", "))
+                } else {
+                    format!(" {{ {}, ..{base_str} }}", sugg.join(", "))
+                },
+            ),
+        };
+        let prefix = if !self.implements_clone(ty) {
+            let msg = format!("`{ty}` doesn't implement `Copy` or `Clone`");
+            if let ty::Adt(def, _) = ty.kind() {
+                err.span_note(self.infcx.tcx.def_span(def.did()), msg);
+            } else {
+                err.note(msg);
+            }
+            format!("if `{ty}` implemented `Clone`, you could ")
+        } else {
+            String::new()
+        };
+        let msg = format!(
+            "{prefix}clone the value from the field instead of using the functional record update \
+             syntax",
+        );
+        err.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable);
+    }
+
+    pub(crate) fn suggest_cloning(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        mut expr: &'cx hir::Expr<'cx>,
+        mut other_expr: Option<&'cx hir::Expr<'cx>>,
+    ) {
+        if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
+            // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
+            // `Location` that covers both the `S { ... }` literal, all of its fields and the
+            // `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr`
+            //  will already be correct. Instead, we see if we can suggest writing.
+            self.suggest_cloning_on_functional_record_update(err, ty, expr);
+            return;
+        }
+
+        if let Some(some_other_expr) = other_expr
+            && let Some(parent_binop) =
+                self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
+                    if let (hir_id, hir::Node::Expr(e)) = n
+                        && let hir::ExprKind::AssignOp(_binop, target, _arg) = e.kind
+                        && target.hir_id == expr.hir_id
+                    {
+                        Some(hir_id)
+                    } else {
+                        None
+                    }
+                })
+            && let Some(other_parent_binop) =
+                self.infcx.tcx.hir().parent_iter(some_other_expr.hir_id).find_map(|n| {
+                    if let (hir_id, hir::Node::Expr(expr)) = n
+                        && let hir::ExprKind::AssignOp(..) = expr.kind
+                    {
+                        Some(hir_id)
+                    } else {
+                        None
+                    }
+                })
+            && parent_binop == other_parent_binop
+        {
+            // Explicitly look for `expr += other_expr;` and avoid suggesting
+            // `expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`.
+            other_expr = Some(expr);
+            expr = some_other_expr;
+        }
+        'outer: {
+            if let ty::Ref(..) = ty.kind() {
+                // We check for either `let binding = foo(expr, other_expr);` or
+                // `foo(expr, other_expr);` and if so we don't suggest an incorrect
+                // `foo(expr, other_expr).clone()`
+                if let Some(other_expr) = other_expr
+                    && let Some(parent_let) =
+                        self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
+                            if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
+                                Some(hir_id)
+                            } else {
+                                None
+                            }
+                        })
+                    && let Some(other_parent_let) =
+                        self.infcx.tcx.hir().parent_iter(other_expr.hir_id).find_map(|n| {
+                            if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
+                                Some(hir_id)
+                            } else {
+                                None
+                            }
+                        })
+                    && parent_let == other_parent_let
+                {
+                    // Explicitly check that we don't have `foo(&*expr, other_expr)`, as cloning the
+                    // result of `foo(...)` won't help.
+                    break 'outer;
+                }
+
+                // We're suggesting `.clone()` on an borrowed value. See if the expression we have
+                // is an argument to a function or method call, and try to suggest cloning the
+                // *result* of the call, instead of the argument. This is closest to what people
+                // would actually be looking for in most cases, with maybe the exception of things
+                // like `fn(T) -> T`, but even then it is reasonable.
+                let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+                let mut prev = expr;
+                while let hir::Node::Expr(parent) = self.infcx.tcx.parent_hir_node(prev.hir_id) {
+                    if let hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) = parent.kind
+                        && let Some(call_ty) = typeck_results.node_type_opt(parent.hir_id)
+                        && let call_ty = call_ty.peel_refs()
+                        && (!call_ty
+                            .walk()
+                            .any(|t| matches!(t.unpack(), ty::GenericArgKind::Lifetime(_)))
+                            || if let ty::Alias(ty::Projection, _) = call_ty.kind() {
+                                // FIXME: this isn't quite right with lifetimes on assoc types,
+                                // but ignore for now. We will only suggest cloning if
+                                // `<Ty as Trait>::Assoc: Clone`, which should keep false positives
+                                // down to a managable ammount.
+                                true
+                            } else {
+                                false
+                            })
+                        && self.implements_clone(call_ty)
+                        && self.suggest_cloning_inner(err, call_ty, parent)
+                    {
+                        return;
+                    }
+                    prev = parent;
+                }
+            }
+        }
+        let ty = ty.peel_refs();
+        if self.implements_clone(ty) {
+            self.suggest_cloning_inner(err, ty, expr);
+        } else if let ty::Adt(def, args) = ty.kind()
+            && def.did().as_local().is_some()
+            && def.variants().iter().all(|variant| {
+                variant
+                    .fields
+                    .iter()
+                    .all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
+            })
+        {
+            err.span_note(
+                self.infcx.tcx.def_span(def.did()),
+                format!("if `{ty}` implemented `Clone`, you could clone the value"),
+            );
+        }
+    }
+
+    fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
+        let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
+        self.infcx
+            .type_implements_trait(clone_trait_def, [ty], self.param_env)
+            .must_apply_modulo_regions()
+    }
+
+    /// Given an expression, check if it is a method call `foo.clone()`, where `foo` and
+    /// `foo.clone()` both have the same type, returning the span for `.clone()` if so.
+    pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
+        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+        if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind
+            && let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id)
+            && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
+            && rcvr_ty == expr_ty
+            && segment.ident.name == sym::clone
+            && args.is_empty()
+        {
+            Some(span)
+        } else {
+            None
+        }
+    }
+
+    fn in_move_closure(&self, expr: &hir::Expr<'_>) -> bool {
+        for (_, node) in self.infcx.tcx.hir().parent_iter(expr.hir_id) {
+            if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = node
+                && let hir::CaptureBy::Value { .. } = closure.capture_clause
+            {
+                // `move || x.clone()` will not work. FIXME: suggest `let y = x.clone(); move || y`
+                return true;
+            }
+        }
+        false
+    }
+
+    fn suggest_cloning_inner(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+    ) -> bool {
         let tcx = self.infcx.tcx;
+        if let Some(_) = self.clone_on_reference(expr) {
+            // Avoid redundant clone suggestion already suggested in `explain_captures`.
+            // See `tests/ui/moves/needs-clone-through-deref.rs`
+            return false;
+        }
+        if self.in_move_closure(expr) {
+            return false;
+        }
         // Try to find predicates on *generic params* that would allow copying `ty`
         let suggestion =
             if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
@@ -996,27 +1323,39 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             } else {
                 ".clone()".to_owned()
             };
-        if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
-            && self
-                .infcx
-                .type_implements_trait(clone_trait_def, [ty], self.param_env)
-                .must_apply_modulo_regions()
+        let mut sugg = Vec::with_capacity(2);
+        let mut inner_expr = expr;
+        // Remove uses of `&` and `*` when suggesting `.clone()`.
+        while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =
+            &inner_expr.kind
         {
-            let msg = if let ty::Adt(def, _) = ty.kind()
-                && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
-                    .contains(&Some(def.did()))
-            {
-                "clone the value to increment its reference count"
-            } else {
-                "consider cloning the value if the performance cost is acceptable"
-            };
-            err.span_suggestion_verbose(
-                span.shrink_to_hi(),
-                msg,
-                suggestion,
-                Applicability::MachineApplicable,
-            );
+            if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind {
+                // We assume that `&mut` refs are desired for their side-effects, so cloning the
+                // value wouldn't do what the user wanted.
+                return false;
+            }
+            inner_expr = inner;
+        }
+        if inner_expr.span.lo() != expr.span.lo() {
+            sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
         }
+        let span = if inner_expr.span.hi() != expr.span.hi() {
+            // Account for `(*x)` to suggest `x.clone()`.
+            expr.span.with_lo(inner_expr.span.hi())
+        } else {
+            expr.span.shrink_to_hi()
+        };
+        sugg.push((span, suggestion));
+        let msg = if let ty::Adt(def, _) = ty.kind()
+            && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
+                .contains(&Some(def.did()))
+        {
+            "clone the value to increment its reference count"
+        } else {
+            "consider cloning the value if the performance cost is acceptable"
+        };
+        err.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable);
+        true
     }
 
     fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
@@ -1121,6 +1460,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 None,
             );
         self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
+        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+        if let Some(expr) = self.find_expr(borrow_span)
+            && let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
+        {
+            self.suggest_cloning(&mut err, ty, expr, self.find_expr(span));
+        }
         self.buffer_error(err);
     }
 
@@ -1469,27 +1814,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let hir = tcx.hir();
         let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
         struct FindUselessClone<'hir> {
+            tcx: TyCtxt<'hir>,
+            def_id: DefId,
             pub clones: Vec<&'hir hir::Expr<'hir>>,
         }
         impl<'hir> FindUselessClone<'hir> {
-            pub fn new() -> Self {
-                Self { clones: vec![] }
+            pub fn new(tcx: TyCtxt<'hir>, def_id: DefId) -> Self {
+                Self { tcx, def_id, clones: vec![] }
             }
         }
 
         impl<'v> Visitor<'v> for FindUselessClone<'v> {
             fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-                // FIXME: use `lookup_method_for_diagnostic`?
                 if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
                     && segment.ident.name == sym::clone
                     && args.len() == 0
+                    && let Some(def_id) = self.def_id.as_local()
+                    && let Some(method) = self.tcx.lookup_method_for_diagnostic((def_id, ex.hir_id))
+                    && Some(self.tcx.parent(method)) == self.tcx.lang_items().clone_trait()
                 {
                     self.clones.push(ex);
                 }
                 hir::intravisit::walk_expr(self, ex);
             }
         }
-        let mut expr_finder = FindUselessClone::new();
+        let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id().into());
 
         let body = hir.body(body_id).value;
         expr_finder.visit_expr(body);
@@ -1538,22 +1887,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
         }
         for ty in types_to_constrain {
-            self.suggest_adding_bounds(err, ty, clone, body.span);
-            if let ty::Adt(..) = ty.kind() {
-                // The type doesn't implement Clone.
-                let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
-                let obligation = Obligation::new(
-                    self.infcx.tcx,
-                    ObligationCause::dummy(),
-                    self.param_env,
-                    trait_ref,
-                );
-                self.infcx.err_ctxt().suggest_derive(
-                    &obligation,
-                    err,
-                    trait_ref.to_predicate(self.infcx.tcx),
-                );
-            }
+            self.suggest_adding_bounds_or_derive(err, ty, clone, body.span);
+        }
+    }
+
+    pub(crate) fn suggest_adding_bounds_or_derive(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        trait_def_id: DefId,
+        span: Span,
+    ) {
+        self.suggest_adding_bounds(err, ty, trait_def_id, span);
+        if let ty::Adt(..) = ty.kind() {
+            // The type doesn't implement the trait.
+            let trait_ref =
+                ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, trait_def_id, [ty]));
+            let obligation = Obligation::new(
+                self.infcx.tcx,
+                ObligationCause::dummy(),
+                self.param_env,
+                trait_ref,
+            );
+            self.infcx.err_ctxt().suggest_derive(
+                &obligation,
+                err,
+                trait_ref.to_predicate(self.infcx.tcx),
+            );
         }
     }
 
@@ -1654,6 +2014,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         );
     }
 
+    pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> {
+        let tcx = self.infcx.tcx;
+        let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
+        let mut expr_finder = FindExprBySpan::new(span);
+        expr_finder.visit_expr(tcx.hir().body(body_id).value);
+        expr_finder.result
+    }
+
     fn suggest_slice_method_if_applicable(
         &self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 0106e285604..dbea317e7bb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -5,6 +5,7 @@ use crate::session_diagnostics::{
     CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
 };
 use rustc_errors::{Applicability, Diag};
+use rustc_errors::{DiagCtxt, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::CoroutineKind;
@@ -29,6 +30,8 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
+use crate::fluent_generated as fluent;
+
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
 
@@ -587,7 +590,7 @@ impl UseSpans<'_> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub(super) fn args_subdiag(
         self,
-        dcx: &rustc_errors::DiagCtxt,
+        dcx: &DiagCtxt,
         err: &mut Diag<'_>,
         f: impl FnOnce(Span) -> CaptureArgLabel,
     ) {
@@ -601,7 +604,7 @@ impl UseSpans<'_> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub(super) fn var_path_only_subdiag(
         self,
-        dcx: &rustc_errors::DiagCtxt,
+        dcx: &DiagCtxt,
         err: &mut Diag<'_>,
         action: crate::InitializationRequiringAction,
     ) {
@@ -639,7 +642,7 @@ impl UseSpans<'_> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub(super) fn var_subdiag(
         self,
-        dcx: &rustc_errors::DiagCtxt,
+        dcx: &DiagCtxt,
         err: &mut Diag<'_>,
         kind: Option<rustc_middle::mir::BorrowKind>,
         f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
@@ -1034,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 .map(|n| format!("`{n}`"))
                 .unwrap_or_else(|| "value".to_owned());
             match kind {
-                CallKind::FnCall { fn_trait_id, .. }
+                CallKind::FnCall { fn_trait_id, self_ty }
                     if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
                 {
                     err.subdiagnostic(
@@ -1046,7 +1049,79 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             is_loop_message,
                         },
                     );
-                    err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
+                    // Check if the move occurs on a value because of a call on a closure that comes
+                    // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:
+                    // ```
+                    // error[E0382]: use of moved value: `blk`
+                    //   --> $DIR/once-cant-call-twice-on-heap.rs:8:5
+                    //    |
+                    // LL | fn foo<F:FnOnce()>(blk: F) {
+                    //    |                    --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
+                    // LL | blk();
+                    //    | ----- `blk` moved due to this call
+                    // LL | blk();
+                    //    | ^^^ value used here after move
+                    //    |
+                    // note: `FnOnce` closures can only be called once
+                    //   --> $DIR/once-cant-call-twice-on-heap.rs:6:10
+                    //    |
+                    // LL | fn foo<F:FnOnce()>(blk: F) {
+                    //    |        ^^^^^^^^ `F` is made to be an `FnOnce` closure here
+                    // LL | blk();
+                    //    | ----- this value implements `FnOnce`, which causes it to be moved when called
+                    // ```
+                    if let ty::Param(param_ty) = self_ty.kind()
+                        && let generics = self.infcx.tcx.generics_of(self.mir_def_id())
+                        && let param = generics.type_param(param_ty, self.infcx.tcx)
+                        && let Some(hir_generics) = self
+                            .infcx
+                            .tcx
+                            .typeck_root_def_id(self.mir_def_id().to_def_id())
+                            .as_local()
+                            .and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
+                        && let spans = hir_generics
+                            .predicates
+                            .iter()
+                            .filter_map(|pred| match pred {
+                                hir::WherePredicate::BoundPredicate(pred) => Some(pred),
+                                _ => None,
+                            })
+                            .filter(|pred| {
+                                if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
+                                    id == param.def_id
+                                } else {
+                                    false
+                                }
+                            })
+                            .flat_map(|pred| pred.bounds)
+                            .filter_map(|bound| {
+                                if let Some(trait_ref) = bound.trait_ref()
+                                    && let Some(trait_def_id) = trait_ref.trait_def_id()
+                                    && trait_def_id == fn_trait_id
+                                {
+                                    Some(bound.span())
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect::<Vec<Span>>()
+                        && !spans.is_empty()
+                    {
+                        let mut span: MultiSpan = spans.clone().into();
+                        for sp in spans {
+                            span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
+                        }
+                        span.push_span_label(
+                            fn_call_span,
+                            fluent::borrowck_moved_a_fn_once_in_call,
+                        );
+                        err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
+                    } else {
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CaptureReasonNote::FnOnceMoveInCall { var_span },
+                        );
+                    }
                 }
                 CallKind::Operator { self_arg, trait_id, .. } => {
                     let self_arg = self_arg.unwrap();
@@ -1212,13 +1287,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 .iter_projections()
                                 .any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
                             {
+                                let (start, end) = if let Some(expr) = self.find_expr(move_span)
+                                    && let Some(_) = self.clone_on_reference(expr)
+                                    && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
+                                {
+                                    (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))
+                                } else {
+                                    (move_span.shrink_to_lo(), move_span.shrink_to_hi())
+                                };
                                 vec![
                                     // We use the fully-qualified path because `.clone()` can
                                     // sometimes choose `<&T as Clone>` instead of `<T as Clone>`
                                     // when going through auto-deref, so this ensures that doesn't
                                     // happen, causing suggestions for `.clone().clone()`.
-                                    (move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
-                                    (move_span.shrink_to_hi(), ")".to_string()),
+                                    (start, format!("<{ty} as Clone>::clone(&")),
+                                    (end, ")".to_string()),
                                 ]
                             } else {
                                 vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 0d1b875cbed..bc02c5be93d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -435,7 +435,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
         match error {
-            GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
+            GroupedMoveError::MovesFromPlace {
+                mut binds_to, move_from, span: other_span, ..
+            } => {
                 self.add_borrow_suggestions(err, span);
                 if binds_to.is_empty() {
                     let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
@@ -444,6 +446,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         None => "value".to_string(),
                     };
 
+                    if let Some(expr) = self.find_expr(span) {
+                        self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span));
+                    }
+
                     err.subdiagnostic(
                         self.dcx(),
                         crate::session_diagnostics::TypeNoCopy::Label {
@@ -468,19 +474,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
             // No binding. Nothing to suggest.
             GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
-                let span = use_spans.var_or_use();
+                let use_span = use_spans.var_or_use();
                 let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
                 let place_desc = match self.describe_place(original_path.as_ref()) {
                     Some(desc) => format!("`{desc}`"),
                     None => "value".to_string(),
                 };
+
+                if let Some(expr) = self.find_expr(use_span) {
+                    self.suggest_cloning(err, place_ty, expr, self.find_expr(span));
+                }
+
                 err.subdiagnostic(
                     self.dcx(),
                     crate::session_diagnostics::TypeNoCopy::Label {
                         is_partial_move: false,
                         ty: place_ty,
                         place: &place_desc,
-                        span,
+                        span: use_span,
                     },
                 );
 
@@ -582,6 +593,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
             if binds_to.len() == 1 {
                 let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
+
+                if let Some(expr) = self.find_expr(binding_span) {
+                    self.suggest_cloning(err, bind_to.ty, expr, None);
+                }
+
                 err.subdiagnostic(
                     self.dcx(),
                     crate::session_diagnostics::TypeNoCopy::Label {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index bd068b29c12..602a84ce4dd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -21,7 +21,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 
 use crate::diagnostics::BorrowedContentSource;
 use crate::util::FindAssignments;
-use crate::MirBorrowckCtxt;
+use crate::{session_diagnostics, MirBorrowckCtxt};
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub(crate) enum AccessKind {
@@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
                         |_kind, var_span| {
                             let place = self.describe_any_place(access_place.as_ref());
-                            crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
+                            session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
                                 place,
                                 var_span,
                             }
@@ -667,19 +667,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// User cannot make signature of a trait mutable without changing the
     /// trait. So we find if this error belongs to a trait and if so we move
     /// suggestion to the trait or disable it if it is out of scope of this crate
-    fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
+    ///
+    /// The returned values are:
+    ///  - is the current item an assoc `fn` of an impl that corresponds to a trait def? if so, we
+    ///    have to suggest changing both the impl `fn` arg and the trait `fn` arg
+    ///  - is the trait from the local crate? If not, we can't suggest changing signatures
+    ///  - `Span` of the argument in the trait definition
+    fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
         if self.body.local_kind(local) != LocalKind::Arg {
-            return (false, None);
+            return (false, false, None);
         }
         let my_def = self.body.source.def_id();
         let my_hir = self.infcx.tcx.local_def_id_to_hir_id(my_def.as_local().unwrap());
         let Some(td) =
             self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
         else {
-            return (false, None);
+            return (false, false, None);
         };
         (
             true,
+            td.is_local(),
             td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
                 Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
                     let mut f_in_trait_opt = None;
@@ -695,19 +702,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         break;
                     }
                     f_in_trait_opt.and_then(|f_in_trait| {
-                        match self.infcx.tcx.hir_node(f_in_trait) {
-                            Node::TraitItem(hir::TraitItem {
-                                kind:
-                                    hir::TraitItemKind::Fn(
-                                        hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
-                                        _,
-                                    ),
-                                ..
-                            }) => {
-                                let hir::Ty { span, .. } = *inputs.get(local.index() - 1)?;
-                                Some(span)
-                            }
-                            _ => None,
+                        if let Node::TraitItem(ti) = self.infcx.tcx.hir_node(f_in_trait)
+                            && let hir::TraitItemKind::Fn(sig, _) = ti.kind
+                            && let Some(ty) = sig.decl.inputs.get(local.index() - 1)
+                            && let hir::TyKind::Ref(_, mut_ty) = ty.kind
+                            && let hir::Mutability::Not = mut_ty.mutbl
+                            && sig.decl.implicit_self.has_implicit_self()
+                        {
+                            Some(ty.span)
+                        } else {
+                            None
                         }
                     })
                 }
@@ -1061,20 +1065,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let (pointer_sigil, pointer_desc) =
             if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
 
-        let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
-        if is_trait_sig && local_trait.is_none() {
+        let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local);
+
+        if is_trait_sig && !is_local {
+            // Do not suggest to change the signature when the trait comes from another crate.
+            err.span_label(
+                local_decl.source_info.span,
+                format!("this is an immutable {pointer_desc}"),
+            );
             return;
         }
-
-        let decl_span = match local_trait {
-            Some(span) => span,
-            None => local_decl.source_info.span,
-        };
+        let decl_span = local_decl.source_info.span;
 
         let label = match *local_decl.local_info() {
             LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
                 let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
-                Some((true, decl_span, suggestion))
+                let additional =
+                    local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span)));
+                Some((true, decl_span, suggestion, additional))
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
@@ -1113,7 +1121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     // don't create labels for compiler-generated spans
                     Some(_) => None,
                     None => {
-                        let label = if name != kw::SelfLower {
+                        let (has_sugg, decl_span, sugg) = if name != kw::SelfLower {
                             suggest_ampmut(
                                 self.infcx.tcx,
                                 local_decl.ty,
@@ -1140,7 +1148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 ),
                             }
                         };
-                        Some(label)
+                        Some((has_sugg, decl_span, sugg, None))
                     }
                 }
             }
@@ -1151,22 +1159,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             })) => {
                 let pattern_span: Span = local_decl.source_info.span;
                 suggest_ref_mut(self.infcx.tcx, pattern_span)
-                    .map(|span| (true, span, "mut ".to_owned()))
+                    .map(|span| (true, span, "mut ".to_owned(), None))
             }
 
             _ => unreachable!(),
         };
 
         match label {
-            Some((true, err_help_span, suggested_code)) => {
-                err.span_suggestion_verbose(
-                    err_help_span,
-                    format!("consider changing this to be a mutable {pointer_desc}"),
-                    suggested_code,
+            Some((true, err_help_span, suggested_code, additional)) => {
+                let mut sugg = vec![(err_help_span, suggested_code)];
+                if let Some(s) = additional {
+                    sugg.push(s);
+                }
+
+                err.multipart_suggestion_verbose(
+                    format!(
+                        "consider changing this to be a mutable {pointer_desc}{}",
+                        if is_trait_sig {
+                            " in the `impl` method and the `trait` definition"
+                        } else {
+                            ""
+                        }
+                    ),
+                    sugg,
                     Applicability::MachineApplicable,
                 );
             }
-            Some((false, err_label_span, message)) => {
+            Some((false, err_label_span, message, _)) => {
                 let def_id = self.body.source.def_id();
                 let hir_id = if let Some(local_def_id) = def_id.as_local()
                     && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index c92fccc959f..304d41d6941 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -26,6 +26,9 @@ use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_middle::ty::{Region, TyCtxt};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use rustc_trait_selection::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
 
 use crate::borrowck_errors;
 use crate::session_diagnostics::{
@@ -810,6 +813,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
         self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
         self.suggest_move_on_borrowing_closure(&mut diag);
+        self.suggest_deref_closure_value(&mut diag);
 
         diag
     }
@@ -1041,6 +1045,147 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
+    /// When encountering a lifetime error caused by the return type of a closure, check the
+    /// corresponding trait bound and see if dereferencing the closure return value would satisfy
+    /// them. If so, we produce a structured suggestion.
+    fn suggest_deref_closure_value(&self, diag: &mut Diag<'_>) {
+        let tcx = self.infcx.tcx;
+        let map = tcx.hir();
+
+        // Get the closure return value and type.
+        let body_id = map.body_owned_by(self.mir_def_id());
+        let body = &map.body(body_id);
+        let value = &body.value.peel_blocks();
+        let hir::Node::Expr(closure_expr) = tcx.hir_node_by_def_id(self.mir_def_id()) else {
+            return;
+        };
+        let fn_call_id = tcx.parent_hir_id(self.mir_hir_id());
+        let hir::Node::Expr(expr) = tcx.hir_node(fn_call_id) else { return };
+        let def_id = map.enclosing_body_owner(fn_call_id);
+        let tables = tcx.typeck(def_id);
+        let Some(return_value_ty) = tables.node_type_opt(value.hir_id) else { return };
+        let return_value_ty = self.infcx.resolve_vars_if_possible(return_value_ty);
+
+        // We don't use `ty.peel_refs()` to get the number of `*`s needed to get the root type.
+        let mut ty = return_value_ty;
+        let mut count = 0;
+        while let ty::Ref(_, t, _) = ty.kind() {
+            ty = *t;
+            count += 1;
+        }
+        if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
+            return;
+        }
+
+        // Build a new closure where the return type is an owned value, instead of a ref.
+        let Some(ty::Closure(did, args)) =
+            tables.node_type_opt(closure_expr.hir_id).as_ref().map(|ty| ty.kind())
+        else {
+            return;
+        };
+        let sig = args.as_closure().sig();
+        let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr(
+            tcx,
+            sig.map_bound(|s| {
+                let unsafety = hir::Unsafety::Normal;
+                use rustc_target::spec::abi;
+                tcx.mk_fn_sig(
+                    [s.inputs()[0]],
+                    s.output().peel_refs(),
+                    s.c_variadic,
+                    unsafety,
+                    abi::Abi::Rust,
+                )
+            }),
+        );
+        let parent_args = GenericArgs::identity_for_item(
+            tcx,
+            tcx.typeck_root_def_id(self.mir_def_id().to_def_id()),
+        );
+        let closure_kind = args.as_closure().kind();
+        let closure_kind_ty = Ty::from_closure_kind(tcx, closure_kind);
+        let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: closure_expr.span,
+        });
+        let closure_args = ty::ClosureArgs::new(
+            tcx,
+            ty::ClosureArgsParts {
+                parent_args,
+                closure_kind_ty,
+                closure_sig_as_fn_ptr_ty,
+                tupled_upvars_ty,
+            },
+        );
+        let closure_ty = Ty::new_closure(tcx, *did, closure_args.args);
+        let closure_ty = tcx.erase_regions(closure_ty);
+
+        let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return };
+        let Some(pos) = args
+            .iter()
+            .enumerate()
+            .find(|(_, arg)| arg.hir_id == closure_expr.hir_id)
+            .map(|(i, _)| i)
+        else {
+            return;
+        };
+        // The found `Self` type of the method call.
+        let Some(possible_rcvr_ty) = tables.node_type_opt(rcvr.hir_id) else { return };
+
+        // The `MethodCall` expression is `Res::Err`, so we search for the method on the `rcvr_ty`.
+        let Some(method) = tcx.lookup_method_for_diagnostic((self.mir_def_id(), expr.hir_id))
+        else {
+            return;
+        };
+
+        // Get the type for the parameter corresponding to the argument the closure with the
+        // lifetime error we had.
+        let Some(input) = tcx
+            .fn_sig(method)
+            .instantiate_identity()
+            .inputs()
+            .skip_binder()
+            // Methods have a `self` arg, so `pos` is actually `+ 1` to match the method call arg.
+            .get(pos + 1)
+        else {
+            return;
+        };
+
+        trace!(?input);
+
+        let ty::Param(closure_param) = input.kind() else { return };
+
+        // Get the arguments for the found method, only specifying that `Self` is the receiver type.
+        let args = GenericArgs::for_item(tcx, method, |param, _| {
+            if param.index == 0 {
+                possible_rcvr_ty.into()
+            } else if param.index == closure_param.index {
+                closure_ty.into()
+            } else {
+                self.infcx.var_for_def(expr.span, param)
+            }
+        });
+
+        let preds = tcx.predicates_of(method).instantiate(tcx, args);
+
+        let ocx = ObligationCtxt::new(&self.infcx);
+        ocx.register_obligations(preds.iter().map(|(pred, span)| {
+            trace!(?pred);
+            Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
+        }));
+
+        if ocx.select_all_or_error().is_empty() {
+            diag.span_suggestion_verbose(
+                value.span.shrink_to_lo(),
+                "dereference the return value",
+                "*".repeat(count),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
         let map = self.infcx.tcx.hir();
         let body_id = map.body_owned_by(self.mir_def_id());
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 61a6361ae8d..c79ae716806 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -196,10 +196,10 @@ pub fn expand_include_str(
         Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
-        Ok(bytes) => match std::str::from_utf8(&bytes) {
+        Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) {
             Ok(src) => {
                 let interned_src = Symbol::intern(src);
-                MacEager::expr(cx.expr_str(sp, interned_src))
+                MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
             }
             Err(_) => {
                 let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
@@ -225,7 +225,9 @@ pub fn expand_include_bytes(
         Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
-        Ok(bytes) => {
+        Ok((bytes, _bsp)) => {
+            // Don't care about getting the span for the raw bytes,
+            // because the console can't really show them anyway.
             let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
             MacEager::expr(expr)
         }
@@ -238,7 +240,7 @@ fn load_binary_file(
     original_path: &Path,
     macro_span: Span,
     path_span: Span,
-) -> Result<Lrc<[u8]>, Box<dyn MacResult>> {
+) -> Result<(Lrc<[u8]>, Span), Box<dyn MacResult>> {
     let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) {
         Ok(path) => path,
         Err(err) => {
@@ -333,10 +335,8 @@ fn find_path_suggestion(
     .flatten()
     .take(4);
 
-    for new_path in root_absolute.chain(add).chain(remove) {
-        if source_map.file_exists(&base_dir.join(&new_path)) {
-            return Some(new_path);
-        }
-    }
-    None
+    root_absolute
+        .chain(add)
+        .chain(remove)
+        .find(|new_path| source_map.file_exists(&base_dir.join(&new_path)))
 }
diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml
index 97c2f45d31e..5a464bfac36 100644
--- a/compiler/rustc_codegen_cranelift/.cirrus.yml
+++ b/compiler/rustc_codegen_cranelift/.cirrus.yml
@@ -7,7 +7,7 @@ task:
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh --default-toolchain none -y --profile=minimal
   target_cache:
-    folder: target
+    folder: build/cg_clif
   prepare_script:
     - . $HOME/.cargo/env
     - ./y.sh prepare
@@ -16,4 +16,5 @@ task:
     # Disabling incr comp reduces cache size and incr comp doesn't save as much
     # on CI anyway.
     - export CARGO_BUILD_INCREMENTAL=false
-    - ./y.sh test
+    # Skip rand as it fails on FreeBSD due to rust-random/rand#1355
+    - ./y.sh test --skip-test test.rust-random/rand
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
index 6fcfca34ea7..1eb2b7f23b2 100644
--- a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
@@ -56,7 +56,7 @@ async function runOnce() {
           force: true,
         });
       } catch (e) {
-        console.log("ERROR: ", JSON.stringify(e.data, null, 2));
+        console.log("ERROR: ", JSON.stringify(e.response, null, 2));
         core.info(`creating dev tag`);
         try {
           await octokit.rest.git.createRef({
@@ -68,7 +68,7 @@ async function runOnce() {
         } catch (e) {
           // we might race with others, so assume someone else has created the
           // tag by this point.
-          console.log("failed to create tag: ", JSON.stringify(e.data, null, 2));
+          console.log("failed to create tag: ", JSON.stringify(e.response, null, 2));
         }
       }
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 913a5c5a850..14aa850ff5c 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -268,6 +268,9 @@ jobs:
     if: ${{ github.ref == 'refs/heads/master' }}
     needs: [rustfmt, test, bench, dist]
 
+    permissions:
+      contents: write # for creating the dev tag and release
+
     concurrency:
       group: release-dev
       cancel-in-progress: true
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index 646928893e9..a3f370af916 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -82,6 +82,19 @@ index d9de37e..8293fce 100644
  #[cfg(target_has_atomic_load_store = "ptr")]
  macro_rules! atomic_int_ptr_sized {
      ( $($target_pointer_width:literal $align:literal)* ) => { $(
+diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
+index 58b9ba4..91bbd0a 100644
+--- a/library/core/src/cell.rs
++++ b/library/core/src/cell.rs
+@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! {
+     u32 "32"
+     i64 "64"
+     u64 "64"
+-    i128 "128"
+-    u128 "128"
+     isize "ptr"
+     usize "ptr"
+ }
 --
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 09e436b3eed..3e7da4e161f 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-04-05"
+channel = "nightly-2024-04-11"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index f42a008dc0c..8580f4557e8 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -10,14 +10,13 @@ pushd rust
 
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
-# FIXME remove this workaround once ICE tests no longer emit an outdated nightly message
-for test in $(rg -i --files-with-matches "//@(\[.*\])? failure-status: 101" tests/ui); do
-  echo "rm $test"
+rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
+for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
-rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
+# should-fail tests don't work when compiletest is compiled with panic=abort
+for test in $(rg --files-with-matches "//@ should-fail" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
@@ -79,7 +78,6 @@ rm -r tests/run-make/fmt-write-bloat/ # tests an optimization
 # ======================
 rm tests/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
 rm -r tests/run-make/cross-lang-lto # same
-rm -r tests/run-make/issue-7349 # same
 rm -r tests/run-make/sepcomp-inlining # same
 rm -r tests/run-make/sepcomp-separate # same
 rm -r tests/run-make/sepcomp-cci-copies # same
@@ -116,8 +114,6 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain
 
 # genuine bugs
 # ============
-rm tests/incremental/spike-neg1.rs # errors out for some reason
-rm tests/incremental/spike-neg2.rs # same
 rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported
 rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 771e5b21958..f07421431da 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -267,10 +267,19 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
         .generic_activity("codegen prelude")
         .run(|| crate::abi::codegen_fn_prelude(fx, start_block));
 
-    for (bb, bb_data) in traversal::mono_reachable(fx.mir, fx.tcx, fx.instance) {
+    let reachable_blocks = traversal::mono_reachable_as_bitset(fx.mir, fx.tcx, fx.instance);
+
+    for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() {
         let block = fx.get_block(bb);
         fx.bcx.switch_to_block(block);
 
+        if !reachable_blocks.contains(bb) {
+            // We want to skip this block, because it's not reachable. But we still create
+            // the block so terminators in other blocks can reference it.
+            fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
+            continue;
+        }
+
         if bb_data.is_cleanup {
             // Unwinding after panicking is not supported
             continue;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index 96ab7a29205..eebd181341d 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -38,6 +38,14 @@ impl UnwindContext {
     }
 
     pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
+        if let target_lexicon::OperatingSystem::MacOSX { .. } = isa.triple().operating_system {
+            // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS
+            // requires for unwinding tables. In addition on arm64 it currently doesn't
+            // support 32bit relocations as we currently use for the unwinding table.
+            // See gimli-rs/object#415 and rust-lang/rustc_codegen_cranelift#1371
+            return;
+        }
+
         let unwind_info = if let Some(unwind_info) =
             context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
         {
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 43cc46cfe68..6253816d37d 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -974,7 +974,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         &mut self,
         place: PlaceRef<'tcx, RValue<'gcc>>,
     ) -> OperandRef<'tcx, RValue<'gcc>> {
-        assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+        assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized());
 
         if place.layout.is_zst() {
             return OperandRef::zero_sized(place.layout);
@@ -999,10 +999,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
             }
         }
 
-        let val = if let Some(llextra) = place.llextra {
-            OperandValue::Ref(place.llval, Some(llextra), place.align)
+        let val = if let Some(_) = place.val.llextra {
+            // FIXME: Merge with the `else` below?
+            OperandValue::Ref(place.val)
         } else if place.layout.is_gcc_immediate() {
-            let load = self.load(place.layout.gcc_type(self), place.llval, place.align);
+            let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align);
             if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
                 scalar_load_metadata(self, load, scalar);
             }
@@ -1012,9 +1013,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
 
             let mut load = |i, scalar: &abi::Scalar, align| {
                 let llptr = if i == 0 {
-                    place.llval
+                    place.val.llval
                 } else {
-                    self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes()))
+                    self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes()))
                 };
                 let llty = place.layout.scalar_pair_element_gcc_type(self, i);
                 let load = self.load(llty, llptr, align);
@@ -1027,11 +1028,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
             };
 
             OperandValue::Pair(
-                load(0, a, place.align),
-                load(1, b, place.align.restrict_for_offset(b_offset)),
+                load(0, a, place.val.align),
+                load(1, b, place.val.align.restrict_for_offset(b_offset)),
             )
         } else {
-            OperandValue::Ref(place.llval, None, place.align)
+            OperandValue::Ref(place.val)
         };
 
         OperandRef { val, layout: place.layout }
@@ -1045,8 +1046,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     ) {
         let zero = self.const_usize(0);
         let count = self.const_usize(count);
-        let start = dest.project_index(self, zero).llval;
-        let end = dest.project_index(self, count).llval;
+        let start = dest.project_index(self, zero).val.llval;
+        let end = dest.project_index(self, count).val.llval;
 
         let header_bb = self.append_sibling_block("repeat_loop_header");
         let body_bb = self.append_sibling_block("repeat_loop_body");
@@ -1064,7 +1065,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.cond_br(keep_going, body_bb, next_bb);
 
         self.switch_to_block(body_bb);
-        let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
+        let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
         cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
 
         let next = self.inbounds_gep(
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index cebd45c09aa..bee6bda007c 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -11,7 +11,7 @@ use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
-use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::{
     ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods,
 };
@@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
 
                 let block = self.llbb();
                 let extended_asm = block.add_extended_asm(None, "");
-                extended_asm.add_input_operand(None, "r", result.llval);
+                extended_asm.add_input_operand(None, "r", result.val.llval);
                 extended_asm.add_clobber("memory");
                 extended_asm.set_volatile_flag(true);
 
@@ -388,8 +388,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         if !fn_abi.ret.is_ignore() {
             if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
                 let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
-                let ptr = self.pointercast(result.llval, ptr_llty);
-                self.store(llval, ptr, result.align);
+                let ptr = self.pointercast(result.val.llval, ptr_llty);
+                self.store(llval, ptr, result.val.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
                     .val
@@ -502,7 +502,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             return;
         }
         if self.is_sized_indirect() {
-            OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
+            OperandValue::Ref(PlaceValue::new_sized(val, self.layout.align.abi)).store(bx, dst)
         } else if self.is_unsized_indirect() {
             bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
         } else if let PassMode::Cast { ref cast, .. } = self.mode {
@@ -511,7 +511,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             let can_store_through_cast_ptr = false;
             if can_store_through_cast_ptr {
                 let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx));
-                let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
+                let cast_dst = bx.pointercast(dst.val.llval, cast_ptr_llty);
                 bx.store(val, cast_dst, self.layout.align.abi);
             } else {
                 // The actual return type is a struct, but the ABI
@@ -539,7 +539,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
 
                 // ... and then memcpy it to the intended destination.
                 bx.memcpy(
-                    dst.llval,
+                    dst.val.llval,
                     self.layout.align.abi,
                     llscratch,
                     scratch_align,
@@ -571,7 +571,12 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
             PassMode::Indirect { meta_attrs: Some(_), .. } => {
-                OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
+                let place_val = PlaceValue {
+                    llval: next(),
+                    llextra: Some(next()),
+                    align: self.layout.align.abi,
+                };
+                OperandValue::Ref(place_val).store(bx, dst);
             }
             PassMode::Direct(_)
             | PassMode::Indirect { meta_attrs: None, .. }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 60361a44c2d..6039a4aaf01 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -82,7 +82,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, '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));
+                let ptr = bx.pointercast(place.val.llval, bx.cx.type_ptr_to(int_ty));
                 bx.load(int_ty, ptr, Align::ONE)
             }
             _ => return_error!(InvalidMonomorphization::InvalidBitmask {
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index f918facc86d..c0b43b77897 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
-use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::MemFlags;
 use rustc_middle::bug;
@@ -207,7 +207,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             // Sized indirect arguments
             PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => {
                 let align = attrs.pointee_align.unwrap_or(self.layout.align.abi);
-                OperandValue::Ref(val, None, align).store(bx, dst);
+                OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst);
             }
             // Unsized indirect qrguments
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
@@ -233,7 +233,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 bx.store(val, llscratch, scratch_align);
                 // ... and then memcpy it to the intended destination.
                 bx.memcpy(
-                    dst.llval,
+                    dst.val.llval,
                     self.layout.align.abi,
                     llscratch,
                     scratch_align,
@@ -265,7 +265,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
-                OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
+                let place_val = PlaceValue {
+                    llval: next(),
+                    llextra: Some(next()),
+                    align: self.layout.align.abi,
+                };
+                OperandValue::Ref(place_val).store(bx, dst);
             }
             PassMode::Direct(_)
             | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 500904ce188..e09869cf425 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -220,7 +220,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         constraints.append(&mut clobbers);
         if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
             match asm_arch {
-                InlineAsmArch::AArch64 | InlineAsmArch::Arm => {
+                InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC | InlineAsmArch::Arm => {
                     constraints.push("~{cc}".to_string());
                 }
                 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index b7235972204..06d9be1869c 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -535,7 +535,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 panic!("unsized locals must not be `extern` types");
             }
         }
-        assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+        assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized());
 
         if place.layout.is_zst() {
             return OperandRef::zero_sized(place.layout);
@@ -579,13 +579,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             }
         }
 
-        let val = if let Some(llextra) = place.llextra {
-            OperandValue::Ref(place.llval, Some(llextra), place.align)
+        let val = if let Some(_) = place.val.llextra {
+            // FIXME: Merge with the `else` below?
+            OperandValue::Ref(place.val)
         } else if place.layout.is_llvm_immediate() {
             let mut const_llval = None;
             let llty = place.layout.llvm_type(self);
             unsafe {
-                if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) {
+                if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
                     if llvm::LLVMIsGlobalConstant(global) == llvm::True {
                         if let Some(init) = llvm::LLVMGetInitializer(global) {
                             if self.val_ty(init) == llty {
@@ -596,7 +597,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 }
             }
             let llval = const_llval.unwrap_or_else(|| {
-                let load = self.load(llty, place.llval, place.align);
+                let load = self.load(llty, place.val.llval, place.val.align);
                 if let abi::Abi::Scalar(scalar) = place.layout.abi {
                     scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO);
                 }
@@ -608,9 +609,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
             let mut load = |i, scalar: abi::Scalar, layout, align, offset| {
                 let llptr = if i == 0 {
-                    place.llval
+                    place.val.llval
                 } else {
-                    self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes()))
+                    self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes()))
                 };
                 let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
                 let load = self.load(llty, llptr, align);
@@ -619,11 +620,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             };
 
             OperandValue::Pair(
-                load(0, a, place.layout, place.align, Size::ZERO),
-                load(1, b, place.layout, place.align.restrict_for_offset(b_offset), b_offset),
+                load(0, a, place.layout, place.val.align, Size::ZERO),
+                load(1, b, place.layout, place.val.align.restrict_for_offset(b_offset), b_offset),
             )
         } else {
-            OperandValue::Ref(place.llval, None, place.align)
+            OperandValue::Ref(place.val)
         };
 
         OperandRef { val, layout: place.layout }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index dc52dd156b7..2bed7c1bd1c 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -264,7 +264,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     llvm::LLVMSetAlignment(load, align);
                 }
                 if !result.layout.is_zst() {
-                    self.store(load, result.llval, result.align);
+                    self.store_to_place(load, result.val);
                 }
                 return Ok(());
             }
@@ -428,7 +428,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
 
             sym::black_box => {
                 args[0].val.store(self, result);
-                let result_val_span = [result.llval];
+                let result_val_span = [result.val.llval];
                 // We need to "use" the argument in some way LLVM can't introspect, and on
                 // targets that support it we can typically leverage inline assembly to do
                 // this. LLVM's interpretation of inline assembly is that it's, well, a black
@@ -482,7 +482,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
 
         if !fn_abi.ret.is_ignore() {
             if let PassMode::Cast { .. } = &fn_abi.ret.mode {
-                self.store(llval, result.llval, result.align);
+                self.store(llval, result.val.llval, result.val.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
                     .val
@@ -1065,7 +1065,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);
-                bx.load(int_ty, place.llval, Align::ONE)
+                bx.load(int_ty, place.val.llval, Align::ONE)
             }
             _ => return_error!(InvalidMonomorphization::InvalidBitmask {
                 span,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ac278de02af..e7d6a671e12 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,6 +11,7 @@ use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
+use rustc_session::config::LinkerFeaturesCli;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, OutFileName, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
@@ -22,10 +23,10 @@ use rustc_session::utils::NativeLibKind;
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::crt_objects::CrtObjects;
-use rustc_target::spec::LinkSelfContainedComponents;
 use rustc_target::spec::LinkSelfContainedDefault;
 use rustc_target::spec::LinkerFlavorCli;
 use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
+use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures};
 use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
 
 use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@@ -42,7 +43,6 @@ use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
 use itertools::Itertools;
-use std::cell::OnceCell;
 use std::collections::BTreeSet;
 use std::ffi::{OsStr, OsString};
 use std::fs::{read, File, OpenOptions};
@@ -52,15 +52,6 @@ use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{env, fmt, fs, io, mem, str};
 
-#[derive(Default)]
-pub struct SearchPaths(OnceCell<Vec<PathBuf>>);
-
-impl SearchPaths {
-    pub(super) fn get(&self, sess: &Session) -> &[PathBuf] {
-        self.0.get_or_init(|| archive_search_paths(sess))
-    }
-}
-
 pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
         if e.kind() != io::ErrorKind::NotFound {
@@ -71,8 +62,8 @@ pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
 
 /// Performs the linkage portion of the compilation phase. This will generate all
 /// of the requested outputs for this compilation session.
-pub fn link_binary<'a>(
-    sess: &'a Session,
+pub fn link_binary(
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     outputs: &OutputFilenames,
@@ -310,8 +301,6 @@ fn link_rlib<'a>(
     flavor: RlibFlavor,
     tmpdir: &MaybeTempDir,
 ) -> Result<Box<dyn ArchiveBuilder + 'a>, ErrorGuaranteed> {
-    let lib_search_paths = archive_search_paths(sess);
-
     let mut ab = archive_builder_builder.new_archive_builder(sess);
 
     let trailing_metadata = match flavor {
@@ -385,19 +374,14 @@ fn link_rlib<'a>(
         if flavor == RlibFlavor::Normal
             && let Some(filename) = lib.filename
         {
-            let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
+            let path = find_native_static_library(filename.as_str(), true, sess);
             let src = read(path)
                 .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?;
             let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
             let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
             packed_bundled_libs.push(wrapper_file);
         } else {
-            let path = find_native_static_library(
-                lib.name.as_str(),
-                lib.verbatim,
-                &lib_search_paths,
-                sess,
-            );
+            let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
             ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
                 sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: path, error })
             });
@@ -464,9 +448,9 @@ fn link_rlib<'a>(
 /// then the CodegenResults value contains one NativeLib instance for each block. However, the
 /// linker appears to expect only a single import library for each library used, so we need to
 /// collate the symbols together by library name before generating the import libraries.
-fn collate_raw_dylibs<'a, 'b>(
-    sess: &'a Session,
-    used_libraries: impl IntoIterator<Item = &'b NativeLib>,
+fn collate_raw_dylibs<'a>(
+    sess: &Session,
+    used_libraries: impl IntoIterator<Item = &'a NativeLib>,
 ) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
     // Use index maps to preserve original order of imports and libraries.
     let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
@@ -513,8 +497,8 @@ fn collate_raw_dylibs<'a, 'b>(
 ///
 /// There's no need to include metadata in a static archive, so ensure to not link in the metadata
 /// object file (and also don't prepare the archive with a metadata file).
-fn link_staticlib<'a>(
-    sess: &'a Session,
+fn link_staticlib(
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     out_filename: &Path,
@@ -626,11 +610,7 @@ fn link_staticlib<'a>(
 
 /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
 /// DWARF package.
-fn link_dwarf_object<'a>(
-    sess: &'a Session,
-    cg_results: &CodegenResults,
-    executable_out_filename: &Path,
-) {
+fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out_filename: &Path) {
     let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string();
     dwp_out_filename.push(".dwp");
     debug!(?dwp_out_filename, ?executable_out_filename);
@@ -734,8 +714,8 @@ fn link_dwarf_object<'a>(
 ///
 /// This will invoke the system linker/cc to create the resulting file. This links to all upstream
 /// files as well.
-fn link_natively<'a>(
-    sess: &'a Session,
+fn link_natively(
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     crate_type: CrateType,
     out_filename: &Path,
@@ -1099,8 +1079,8 @@ fn link_natively<'a>(
     Ok(())
 }
 
-fn strip_symbols_with_external_utility<'a>(
-    sess: &'a Session,
+fn strip_symbols_with_external_utility(
+    sess: &Session,
     util: &str,
     out_filename: &Path,
     option: Option<&str>,
@@ -1337,7 +1317,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
         sess: &Session,
         linker: Option<PathBuf>,
         flavor: Option<LinkerFlavor>,
+        features: LinkerFeaturesCli,
     ) -> Option<(PathBuf, LinkerFlavor)> {
+        let flavor = flavor.map(|flavor| adjust_flavor_to_features(flavor, features));
         match (linker, flavor) {
             (Some(linker), Some(flavor)) => Some((linker, flavor)),
             // only the linker flavor is known; use the default linker for the selected flavor
@@ -1385,12 +1367,33 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     sess.dcx().emit_fatal(errors::LinkerFileStem);
                 });
                 let flavor = sess.target.linker_flavor.with_linker_hints(stem);
+                let flavor = adjust_flavor_to_features(flavor, features);
                 Some((linker, flavor))
             }
             (None, None) => None,
         }
     }
 
+    // While linker flavors and linker features are isomorphic (and thus targets don't need to
+    // define features separately), we use the flavor as the root piece of data and have the
+    // linker-features CLI flag influence *that*, so that downstream code does not have to check for
+    // both yet.
+    fn adjust_flavor_to_features(
+        flavor: LinkerFlavor,
+        features: LinkerFeaturesCli,
+    ) -> LinkerFlavor {
+        // Note: a linker feature cannot be both enabled and disabled on the CLI.
+        if features.enabled.contains(LinkerFeatures::LLD) {
+            flavor.with_lld_enabled()
+        } else if features.disabled.contains(LinkerFeatures::LLD) {
+            flavor.with_lld_disabled()
+        } else {
+            flavor
+        }
+    }
+
+    let features = sess.opts.unstable_opts.linker_features;
+
     // linker and linker flavor specified via command line have precedence over what the target
     // specification specifies
     let linker_flavor = match sess.opts.cg.linker_flavor {
@@ -1404,7 +1407,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
             .linker_flavor
             .map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor)),
     };
-    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
+    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor, features) {
         return ret;
     }
 
@@ -1412,6 +1415,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
         sess,
         sess.target.linker.as_deref().map(PathBuf::from),
         Some(sess.target.linker_flavor),
+        features,
     ) {
         return ret;
     }
@@ -1445,10 +1449,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
     }
 }
 
-fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
-    sess.target_filesearch(PathKind::Native).search_path_dirs()
-}
-
 #[derive(PartialEq)]
 enum RlibFlavor {
     Normal,
@@ -2108,10 +2108,10 @@ fn add_rpath_args(
 /// to the linking process as a whole.
 /// Order-independent options may still override each other in order-dependent fashion,
 /// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
-fn linker_with_args<'a>(
+fn linker_with_args(
     path: &Path,
     flavor: LinkerFlavor,
-    sess: &'a Session,
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     crate_type: CrateType,
     tmpdir: &Path,
@@ -2500,7 +2500,6 @@ fn add_native_libs_from_crate(
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-    search_paths: &SearchPaths,
     bundled_libs: &FxIndexSet<Symbol>,
     cnum: CrateNum,
     link_static: bool,
@@ -2563,7 +2562,7 @@ fn add_native_libs_from_crate(
                             cmd.link_staticlib_by_path(&path, whole_archive);
                         }
                     } else {
-                        cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths);
+                        cmd.link_staticlib_by_name(name, verbatim, whole_archive);
                     }
                 }
             }
@@ -2577,7 +2576,7 @@ fn add_native_libs_from_crate(
                 // link kind is unspecified.
                 if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs {
                     if link_static {
-                        cmd.link_staticlib_by_name(name, verbatim, false, search_paths);
+                        cmd.link_staticlib_by_name(name, verbatim, false);
                     }
                 } else {
                     if link_dynamic {
@@ -2624,7 +2623,6 @@ fn add_local_native_libraries(
         }
     }
 
-    let search_paths = SearchPaths::default();
     // All static and dynamic native library dependencies are linked to the local crate.
     let link_static = true;
     let link_dynamic = true;
@@ -2634,7 +2632,6 @@ fn add_local_native_libraries(
         archive_builder_builder,
         codegen_results,
         tmpdir,
-        &search_paths,
         &Default::default(),
         LOCAL_CRATE,
         link_static,
@@ -2643,9 +2640,9 @@ fn add_local_native_libraries(
     );
 }
 
-fn add_upstream_rust_crates<'a>(
+fn add_upstream_rust_crates(
     cmd: &mut dyn Linker,
-    sess: &'a Session,
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     crate_type: CrateType,
@@ -2666,7 +2663,6 @@ fn add_upstream_rust_crates<'a>(
         .find(|(ty, _)| *ty == crate_type)
         .expect("failed to find crate type in dependency format list");
 
-    let search_paths = SearchPaths::default();
     for &cnum in &codegen_results.crate_info.used_crates {
         // We may not pass all crates through to the linker. Some crates may appear statically in
         // an existing dylib, meaning we'll pick up all the symbols from the dylib.
@@ -2723,7 +2719,6 @@ fn add_upstream_rust_crates<'a>(
             archive_builder_builder,
             codegen_results,
             tmpdir,
-            &search_paths,
             &bundled_libs,
             cnum,
             link_static,
@@ -2741,7 +2736,6 @@ fn add_upstream_native_libraries(
     tmpdir: &Path,
     link_output_kind: LinkOutputKind,
 ) {
-    let search_paths = SearchPaths::default();
     for &cnum in &codegen_results.crate_info.used_crates {
         // Static libraries are not linked here, they are linked in `add_upstream_rust_crates`.
         // FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries
@@ -2763,7 +2757,6 @@ fn add_upstream_native_libraries(
             archive_builder_builder,
             codegen_results,
             tmpdir,
-            &search_paths,
             &Default::default(),
             cnum,
             link_static,
@@ -2782,7 +2775,7 @@ fn add_upstream_native_libraries(
 // file generated by the MSVC linker. See https://github.com/rust-lang/rust/issues/112586.
 //
 // The returned path will always have `fix_windows_verbatim_for_gcc()` applied to it.
-fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
+fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf {
     let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
     let canonical_sysroot_lib_path =
         { try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
@@ -2815,9 +2808,9 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
 // Note, however, that if we're not doing LTO we can just pass the rlib
 // blindly to the linker (fast) because it's fine if it's not actually
 // included as we're at the end of the dependency chain.
-fn add_static_crate<'a>(
+fn add_static_crate(
     cmd: &mut dyn Linker,
-    sess: &'a Session,
+    sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
@@ -2990,13 +2983,29 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
 
     match flavor {
         LinkerFlavor::Darwin(Cc::Yes, _) => {
-            cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+            // Use `-isysroot` instead of `--sysroot`, as only the former
+            // makes Clang treat it as a platform SDK.
+            //
+            // This is admittedly a bit strange, as on most targets
+            // `-isysroot` only applies to include header files, but on Apple
+            // targets this also applies to libraries and frameworks.
+            cmd.args(&["-isysroot", &sdk_root]);
         }
         LinkerFlavor::Darwin(Cc::No, _) => {
             cmd.args(&["-syslibroot", &sdk_root]);
         }
         _ => unreachable!(),
     }
+
+    if llvm_target.contains("macabi") {
+        // Mac Catalyst uses the macOS SDK, but to link to iOS-specific
+        // frameworks, we must have the support library stubs in the library
+        // search path.
+
+        // The flags are called `-L` and `-F` both in Clang, ld64 and ldd.
+        cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib"));
+        cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks"));
+    }
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootError<'_>> {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index f5640ea26bc..fad6f439441 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,6 +1,5 @@
 use super::command::Command;
 use super::symbol_export;
-use crate::back::link::SearchPaths;
 use crate::errors;
 use rustc_span::symbol::sym;
 
@@ -172,13 +171,7 @@ pub trait Linker {
     fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
         bug!("framework linked with unsupported linker")
     }
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        verbatim: bool,
-        whole_archive: bool,
-        search_paths: &SearchPaths,
-    );
+    fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
@@ -482,13 +475,7 @@ impl<'a> Linker for GccLinker<'a> {
         self.cmd.arg("-framework").arg(name);
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        verbatim: bool,
-        whole_archive: bool,
-        search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         let colon = if verbatim && self.is_gnu { ":" } else { "" };
         if !whole_archive {
@@ -497,8 +484,7 @@ impl<'a> Linker for GccLinker<'a> {
             // -force_load is the macOS equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
             self.linker_arg("-force_load");
-            let search_paths = search_paths.get(self.sess);
-            self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess));
+            self.linker_arg(find_native_static_library(name, verbatim, self.sess));
         } else {
             self.linker_arg("--whole-archive");
             self.cmd.arg(format!("-l{colon}{name}"));
@@ -825,13 +811,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        verbatim: bool,
-        whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
         let suffix = if verbatim { "" } else { ".lib" };
         self.cmd.arg(format!("{prefix}{name}{suffix}"));
@@ -1064,13 +1044,7 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg("-l").arg(name);
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        _verbatim: bool,
-        _whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
         self.cmd.arg("-l").arg(name);
     }
 
@@ -1243,13 +1217,7 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg("-l").arg(name);
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        _verbatim: bool,
-        whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         if !whole_archive {
             self.cmd.arg("-l").arg(name);
         } else {
@@ -1396,13 +1364,7 @@ impl<'a> Linker for L4Bender<'a> {
         bug!("dylibs are not supported on L4Re");
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        _verbatim: bool,
-        whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
             self.cmd.arg(format!("-PC{name}"));
@@ -1580,20 +1542,13 @@ impl<'a> Linker for AixLinker<'a> {
         self.cmd.arg(format!("-l{name}"));
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        name: &str,
-        verbatim: bool,
-        whole_archive: bool,
-        search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
             self.cmd.arg(format!("-l{name}"));
         } else {
             let mut arg = OsString::from("-bkeepfile:");
-            let search_path = search_paths.get(self.sess);
-            arg.push(find_native_static_library(name, verbatim, search_path, self.sess));
+            arg.push(find_native_static_library(name, verbatim, self.sess));
             self.cmd.arg(arg);
         }
     }
@@ -1792,13 +1747,7 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        _name: &str,
-        _verbatim: bool,
-        _whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
@@ -1880,13 +1829,7 @@ impl<'a> Linker for LlbcLinker<'a> {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        _name: &str,
-        _verbatim: bool,
-        _whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
@@ -1977,13 +1920,7 @@ impl<'a> Linker for BpfLinker<'a> {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib_by_name(
-        &mut self,
-        _name: &str,
-        _verbatim: bool,
-        _whole_archive: bool,
-        _search_paths: &SearchPaths,
-    ) {
+    fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c3137f0628e..24f2c50e882 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1,6 +1,6 @@
 use super::operand::OperandRef;
 use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
-use super::place::PlaceRef;
+use super::place::{PlaceRef, PlaceValue};
 use super::{CachedLlbb, FunctionCx, LocalRef};
 
 use crate::base;
@@ -242,7 +242,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
                 bx.switch_to_block(fx.llbb(target));
                 fx.set_debug_loc(bx, self.terminator.source_info);
                 for tmp in copied_constant_arguments {
-                    bx.lifetime_end(tmp.llval, tmp.layout.size);
+                    bx.lifetime_end(tmp.val.llval, tmp.layout.size);
                 }
                 fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret);
             }
@@ -256,7 +256,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
 
             if let Some((ret_dest, target)) = destination {
                 for tmp in copied_constant_arguments {
-                    bx.lifetime_end(tmp.llval, tmp.layout.size);
+                    bx.lifetime_end(tmp.val.llval, tmp.layout.size);
                 }
                 fx.store_return(bx, ret_dest, &fn_abi.ret, llret);
                 self.funclet_br(fx, bx, target, mergeable_succ)
@@ -431,7 +431,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let va_list_arg_idx = self.fn_abi.args.len();
             match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] {
                 LocalRef::Place(va_list) => {
-                    bx.va_end(va_list.llval);
+                    bx.va_end(va_list.val.llval);
                 }
                 _ => bug!("C-variadic function must have a `VaList` place"),
             }
@@ -455,8 +455,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             PassMode::Direct(_) | PassMode::Pair(..) => {
                 let op = self.codegen_consume(bx, mir::Place::return_place().as_ref());
-                if let Ref(llval, _, align) = op.val {
-                    bx.load(bx.backend_type(op.layout), llval, align)
+                if let Ref(place_val) = op.val {
+                    bx.load_from_place(bx.backend_type(op.layout), place_val)
                 } else {
                     op.immediate_or_packed_pair(bx)
                 }
@@ -466,21 +466,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let op = match self.locals[mir::RETURN_PLACE] {
                     LocalRef::Operand(op) => op,
                     LocalRef::PendingOperand => bug!("use of return before def"),
-                    LocalRef::Place(cg_place) => OperandRef {
-                        val: Ref(cg_place.llval, None, cg_place.align),
-                        layout: cg_place.layout,
-                    },
+                    LocalRef::Place(cg_place) => {
+                        OperandRef { val: Ref(cg_place.val), layout: cg_place.layout }
+                    }
                     LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
                 };
                 let llslot = match op.val {
                     Immediate(_) | Pair(..) => {
                         let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout);
                         op.val.store(bx, scratch);
-                        scratch.llval
+                        scratch.val.llval
                     }
-                    Ref(llval, _, align) => {
-                        assert_eq!(align, op.layout.align.abi, "return place is unaligned!");
-                        llval
+                    Ref(place_val) => {
+                        assert_eq!(
+                            place_val.align, op.layout.align.abi,
+                            "return place is unaligned!"
+                        );
+                        place_val.llval
                     }
                     ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
                 };
@@ -512,11 +514,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let place = self.codegen_place(bx, location.as_ref());
         let (args1, args2);
-        let mut args = if let Some(llextra) = place.llextra {
-            args2 = [place.llval, llextra];
+        let mut args = if let Some(llextra) = place.val.llextra {
+            args2 = [place.val.llval, llextra];
             &args2[..]
         } else {
-            args1 = [place.llval];
+            args1 = [place.val.llval];
             &args1[..]
         };
         let (drop_fn, fn_abi, drop_instance) =
@@ -918,7 +920,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let dest = match ret_dest {
                     _ if fn_abi.ret.is_indirect() => llargs[0],
                     ReturnDest::Nothing => bx.const_undef(bx.type_ptr()),
-                    ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
+                    ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.val.llval,
                     ReturnDest::DirectOperand(_) => {
                         bug!("Cannot use direct operand with an intrinsic call")
                     }
@@ -951,7 +953,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) {
                     Ok(()) => {
                         if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
-                            self.store_return(bx, ret_dest, &fn_abi.ret, dst.llval);
+                            self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval);
                         }
 
                         return if let Some(target) = target {
@@ -1032,7 +1034,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         llargs.push(data_ptr);
                         continue 'make_args;
                     }
-                    Ref(data_ptr, Some(meta), _) => {
+                    Ref(PlaceValue { llval: data_ptr, llextra: Some(meta), .. }) => {
                         // by-value dynamic dispatch
                         llfn = Some(meth::VirtualIndex::from_index(idx).get_fn(
                             bx,
@@ -1058,16 +1060,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             span_bug!(span, "can't codegen a virtual call on {:#?}", op);
                         }
                         let place = op.deref(bx.cx());
-                        let data_ptr = place.project_field(bx, 0);
-                        let meta_ptr = place.project_field(bx, 1);
-                        let meta = bx.load_operand(meta_ptr);
+                        let data_place = place.project_field(bx, 0);
+                        let meta_place = place.project_field(bx, 1);
+                        let meta = bx.load_operand(meta_place);
                         llfn = Some(meth::VirtualIndex::from_index(idx).get_fn(
                             bx,
                             meta.immediate(),
                             op.layout.ty,
                             fn_abi,
                         ));
-                        llargs.push(data_ptr.llval);
+                        llargs.push(data_place.val.llval);
                         continue;
                     }
                     _ => {
@@ -1079,12 +1081,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // The callee needs to own the argument memory if we pass it
             // by-ref, so make a local copy of non-immediate constants.
             match (&arg.node, op.val) {
-                (&mir::Operand::Copy(_), Ref(_, None, _))
-                | (&mir::Operand::Constant(_), Ref(_, None, _)) => {
+                (&mir::Operand::Copy(_), Ref(PlaceValue { llextra: None, .. }))
+                | (&mir::Operand::Constant(_), Ref(PlaceValue { llextra: None, .. })) => {
                     let tmp = PlaceRef::alloca(bx, op.layout);
-                    bx.lifetime_start(tmp.llval, tmp.layout.size);
+                    bx.lifetime_start(tmp.val.llval, tmp.layout.size);
                     op.val.store(bx, tmp);
-                    op.val = Ref(tmp.llval, None, tmp.align);
+                    op.val = Ref(tmp.val);
                     copied_constant_arguments.push(tmp);
                 }
                 _ => {}
@@ -1428,7 +1430,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 _ => bug!("codegen_argument: {:?} invalid for pair argument", op),
             },
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val {
-                Ref(a, Some(b), _) => {
+                Ref(PlaceValue { llval: a, llextra: Some(b), .. }) => {
                     llargs.push(a);
                     llargs.push(b);
                     return;
@@ -1450,34 +1452,34 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     };
                     let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
                     op.val.store(bx, scratch);
-                    (scratch.llval, scratch.align, true)
+                    (scratch.val.llval, scratch.val.align, true)
                 }
                 PassMode::Cast { .. } => {
                     let scratch = PlaceRef::alloca(bx, arg.layout);
                     op.val.store(bx, scratch);
-                    (scratch.llval, scratch.align, true)
+                    (scratch.val.llval, scratch.val.align, true)
                 }
                 _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false),
             },
-            Ref(llval, llextra, align) => match arg.mode {
+            Ref(op_place_val) => match arg.mode {
                 PassMode::Indirect { attrs, .. } => {
                     let required_align = match attrs.pointee_align {
                         Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi),
                         None => arg.layout.align.abi,
                     };
-                    if align < required_align {
+                    if op_place_val.align < required_align {
                         // For `foo(packed.large_field)`, and types with <4 byte alignment on x86,
                         // alignment requirements may be higher than the type's alignment, so copy
                         // to a higher-aligned alloca.
                         let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
-                        let op_place = PlaceRef { llval, llextra, layout: op.layout, align };
+                        let op_place = PlaceRef { val: op_place_val, layout: op.layout };
                         bx.typed_place_copy(scratch, op_place);
-                        (scratch.llval, scratch.align, true)
+                        (scratch.val.llval, scratch.val.align, true)
                     } else {
-                        (llval, align, true)
+                        (op_place_val.llval, op_place_val.align, true)
                     }
                 }
-                _ => (llval, align, true),
+                _ => (op_place_val.llval, op_place_val.align, true),
             },
             ZeroSized => match arg.mode {
                 PassMode::Indirect { on_stack, .. } => {
@@ -1490,7 +1492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     // a pointer for `repr(C)` structs even when empty, so get
                     // one from an `alloca` (which can be left uninitialized).
                     let scratch = PlaceRef::alloca(bx, arg.layout);
-                    (scratch.llval, scratch.align, true)
+                    (scratch.val.llval, scratch.val.align, true)
                 }
                 _ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"),
             },
@@ -1557,15 +1559,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let tuple = self.codegen_operand(bx, operand);
 
         // Handle both by-ref and immediate tuples.
-        if let Ref(llval, None, align) = tuple.val {
-            let tuple_ptr = PlaceRef::new_sized_aligned(llval, tuple.layout, align);
+        if let Ref(place_val) = tuple.val {
+            if place_val.llextra.is_some() {
+                bug!("closure arguments must be sized");
+            }
+            let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout };
             for i in 0..tuple.layout.fields.count() {
                 let field_ptr = tuple_ptr.project_field(bx, i);
                 let field = bx.load_operand(field_ptr);
                 self.codegen_argument(bx, field, llargs, &args[i]);
             }
-        } else if let Ref(_, Some(_), _) = tuple.val {
-            bug!("closure arguments must be sized")
         } else {
             // If the tuple is immediate, the elements are as well.
             for i in 0..tuple.layout.fields.count() {
@@ -1782,7 +1785,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // but the calling convention has an indirect return.
                         let tmp = PlaceRef::alloca(bx, fn_ret.layout);
                         tmp.storage_live(bx);
-                        llargs.push(tmp.llval);
+                        llargs.push(tmp.val.llval);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else if intrinsic.is_some() {
                         // Currently, intrinsics always need a location to store
@@ -1803,7 +1806,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection })
         };
         if fn_ret.is_indirect() {
-            if dest.align < dest.layout.align.abi {
+            if dest.val.align < dest.layout.align.abi {
                 // Currently, MIR code generation does not create calls
                 // that store directly to fields of packed structs (in
                 // fact, the calls it creates write only to temps).
@@ -1812,7 +1815,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // to create a temporary.
                 span_bug!(self.mir.span, "can't directly store to unaligned value");
             }
-            llargs.push(dest.llval);
+            llargs.push(dest.val.llval);
             ReturnDest::Nothing
         } else {
             ReturnDest::Store(dest)
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 0387c430d32..a5fd82a3054 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -14,7 +14,7 @@ use rustc_span::{BytePos, Span};
 use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};
 
 use super::operand::{OperandRef, OperandValue};
-use super::place::PlaceRef;
+use super::place::{PlaceRef, PlaceValue};
 use super::{FunctionCx, LocalRef};
 
 use std::ops::Range;
@@ -252,7 +252,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // at least for the cases which LLVM handles correctly.
         let spill_slot = PlaceRef::alloca(bx, operand.layout);
         if let Some(name) = name {
-            bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
+            bx.set_var_name(spill_slot.val.llval, &(name + ".dbg.spill"));
         }
         operand.val.store(bx, spill_slot);
         spill_slot
@@ -331,10 +331,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if let Some(name) = &name {
             match local_ref {
                 LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
-                    bx.set_var_name(place.llval, name);
+                    bx.set_var_name(place.val.llval, name);
                 }
                 LocalRef::Operand(operand) => match operand.val {
-                    OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => {
+                    OperandValue::Ref(PlaceValue { llval: x, .. }) | OperandValue::Immediate(x) => {
                         bx.set_var_name(x, name);
                     }
                     OperandValue::Pair(a, b) => {
@@ -417,16 +417,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
             let ptr_layout = bx.layout_of(ptr_ty);
             let alloca = PlaceRef::alloca(bx, ptr_layout);
-            bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill"));
+            bx.set_var_name(alloca.val.llval, &(var.name.to_string() + ".dbg.spill"));
 
             // Write the pointer to the variable
-            bx.store(place.llval, alloca.llval, alloca.align);
+            bx.store_to_place(place.val.llval, alloca.val);
 
             // Point the debug info to `*alloca` for the current variable
             bx.dbg_var_addr(
                 dbg_var,
                 dbg_loc,
-                alloca.llval,
+                alloca.val.llval,
                 Size::ZERO,
                 &[Size::ZERO],
                 var.fragment,
@@ -435,7 +435,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             bx.dbg_var_addr(
                 dbg_var,
                 dbg_loc,
-                base.llval,
+                base.val.llval,
                 direct_offset,
                 &indirect_offsets,
                 var.fragment,
@@ -553,7 +553,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let base =
                             Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
 
-                        bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
+                        bx.dbg_var_addr(
+                            dbg_var,
+                            dbg_loc,
+                            base.val.llval,
+                            Size::ZERO,
+                            &[],
+                            fragment,
+                        );
                     }
                 }
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 3e6cf0ece29..eb14a90412d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -387,9 +387,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             let success = bx.from_immediate(success);
 
                             let dest = result.project_field(bx, 0);
-                            bx.store(val, dest.llval, dest.align);
+                            bx.store_to_place(val, dest.val);
                             let dest = result.project_field(bx, 1);
-                            bx.store(success, dest.llval, dest.align);
+                            bx.store_to_place(success, dest.val);
                         } else {
                             invalid_monomorphization(ty);
                         }
@@ -511,7 +511,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         if !fn_abi.ret.is_ignore() {
             if let PassMode::Cast { .. } = &fn_abi.ret.mode {
-                bx.store(llval, result.llval, result.align);
+                bx.store_to_place(llval, result.val);
             } else {
                 OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
                     .val
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 1f4473d2ec4..b98e90b5cde 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -2,6 +2,7 @@ use crate::base;
 use crate::traits::*;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::UnwindTerminateReason;
@@ -289,6 +290,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let mut num_untupled = None;
 
+    let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id());
+    let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED);
+    if naked {
+        return vec![];
+    }
+
     let args = mir
         .args_iter()
         .enumerate()
@@ -336,7 +343,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
                 let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
-                bx.va_start(va_list.llval);
+                bx.va_start(va_list.val.llval);
 
                 return LocalRef::Place(va_list);
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index ac38b91c5e0..9cf64e2d676 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -1,4 +1,4 @@
-use super::place::PlaceRef;
+use super::place::{PlaceRef, PlaceValue};
 use super::{FunctionCx, LocalRef};
 
 use crate::size_of_val;
@@ -23,11 +23,14 @@ pub enum OperandValue<V> {
     /// The second value, if any, is the extra data (vtable or length)
     /// which indicates that it refers to an unsized rvalue.
     ///
-    /// An `OperandValue` has this variant for types which are neither
-    /// `Immediate` nor `Pair`s. The backend value in this variant must be a
-    /// pointer to the *non*-immediate backend type. That pointee type is the
+    /// An `OperandValue` *must* be this variant for any type for which
+    /// [`LayoutTypeMethods::is_backend_ref`] returns `true`.
+    /// (That basically amounts to "isn't one of the other variants".)
+    ///
+    /// This holds a [`PlaceValue`] (like a [`PlaceRef`] does) with a pointer
+    /// to the location holding the value. The type behind that pointer is the
     /// one returned by [`LayoutTypeMethods::backend_type`].
-    Ref(V, Option<V>, Align),
+    Ref(PlaceValue<V>),
     /// A single LLVM immediate value.
     ///
     /// An `OperandValue` *must* be this variant for any type for which
@@ -221,7 +224,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
         };
         let layout = cx.layout_of(projected_ty);
-        PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi }
+        let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi };
+        PlaceRef { val, layout }
     }
 
     /// If this operand is a `Pair`, we return an aggregate with the two values.
@@ -361,7 +365,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
             OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
         } else {
             let ptr = bx.cx().type_ptr();
-            OperandValue::Ref(bx.const_poison(ptr), None, layout.align.abi)
+            OperandValue::Ref(PlaceValue::new_sized(bx.const_poison(ptr), layout.align.abi))
         }
     }
 
@@ -409,18 +413,17 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
                 // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
                 // value is through `undef`/`poison`, and the store itself is useless.
             }
-            OperandValue::Ref(llval, llextra @ None, source_align) => {
+            OperandValue::Ref(val) => {
                 assert!(dest.layout.is_sized(), "cannot directly store unsized values");
-                let source_place =
-                    PlaceRef { llval, llextra, align: source_align, layout: dest.layout };
+                if val.llextra.is_some() {
+                    bug!("cannot directly store unsized values");
+                }
+                let source_place = PlaceRef { val, layout: dest.layout };
                 bx.typed_place_copy_with_flags(dest, source_place, flags);
             }
-            OperandValue::Ref(_, Some(_), _) => {
-                bug!("cannot directly store unsized values");
-            }
             OperandValue::Immediate(s) => {
                 let val = bx.from_immediate(s);
-                bx.store_with_flags(val, dest.llval, dest.align, flags);
+                bx.store_with_flags(val, dest.val.llval, dest.val.align, flags);
             }
             OperandValue::Pair(a, b) => {
                 let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else {
@@ -429,12 +432,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
                 let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
 
                 let val = bx.from_immediate(a);
-                let align = dest.align;
-                bx.store_with_flags(val, dest.llval, align, flags);
+                let align = dest.val.align;
+                bx.store_with_flags(val, dest.val.llval, align, flags);
 
-                let llptr = bx.inbounds_ptradd(dest.llval, bx.const_usize(b_offset.bytes()));
+                let llptr = bx.inbounds_ptradd(dest.val.llval, bx.const_usize(b_offset.bytes()));
                 let val = bx.from_immediate(b);
-                let align = dest.align.restrict_for_offset(b_offset);
+                let align = dest.val.align.restrict_for_offset(b_offset);
                 bx.store_with_flags(val, llptr, align, flags);
             }
         }
@@ -454,7 +457,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
             .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
             .ty;
 
-        let OperandValue::Ref(llptr, Some(llextra), _) = self else {
+        let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
+        else {
             bug!("store_unsized called with a sized value (or with an extern type)")
         };
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 1ec6c351e25..90627da579e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -12,25 +12,48 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
+/// The location and extra runtime properties of the place.
+///
+/// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
 #[derive(Copy, Clone, Debug)]
-pub struct PlaceRef<'tcx, V> {
+pub struct PlaceValue<V> {
     /// A pointer to the contents of the place.
     pub llval: V,
 
     /// This place's extra data if it is unsized, or `None` if null.
     pub llextra: Option<V>,
 
-    /// The monomorphized type of this place, including variant information.
-    pub layout: TyAndLayout<'tcx>,
-
     /// The alignment we know for this place.
     pub align: Align,
 }
 
+impl<V: CodegenObject> PlaceValue<V> {
+    /// Constructor for the ordinary case of `Sized` types.
+    ///
+    /// Sets `llextra` to `None`.
+    pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> {
+        PlaceValue { llval, llextra: None, align }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct PlaceRef<'tcx, V> {
+    /// The location and extra runtime properties of the place.
+    pub val: PlaceValue<V>,
+
+    /// The monomorphized type of this place, including variant information.
+    ///
+    /// You probably shouldn't use the alignment from this layout;
+    /// rather you should use the `.val.align` of the actual place,
+    /// which might be different from the type's normal alignment.
+    pub layout: TyAndLayout<'tcx>,
+}
+
 impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
         assert!(layout.is_sized());
-        PlaceRef { llval, llextra: None, layout, align: layout.align.abi }
+        let val = PlaceValue::new_sized(llval, layout.align.abi);
+        PlaceRef { val, layout }
     }
 
     pub fn new_sized_aligned(
@@ -39,7 +62,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         align: Align,
     ) -> PlaceRef<'tcx, V> {
         assert!(layout.is_sized());
-        PlaceRef { llval, llextra: None, layout, align }
+        let val = PlaceValue::new_sized(llval, align);
+        PlaceRef { val, layout }
     }
 
     // FIXME(eddyb) pass something else for the name so no work is done
@@ -78,7 +102,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         if let FieldsShape::Array { count, .. } = self.layout.fields {
             if self.layout.is_unsized() {
                 assert_eq!(count, 0);
-                self.llextra.unwrap()
+                self.val.llextra.unwrap()
             } else {
                 cx.const_usize(count)
             }
@@ -97,21 +121,27 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     ) -> Self {
         let field = self.layout.field(bx.cx(), ix);
         let offset = self.layout.fields.offset(ix);
-        let effective_field_align = self.align.restrict_for_offset(offset);
+        let effective_field_align = self.val.align.restrict_for_offset(offset);
 
         // `simple` is called when we don't need to adjust the offset to
         // the dynamic alignment of the field.
         let mut simple = || {
             let llval = if offset.bytes() == 0 {
-                self.llval
+                self.val.llval
             } else {
-                bx.inbounds_ptradd(self.llval, bx.const_usize(offset.bytes()))
+                bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes()))
             };
             PlaceRef {
-                llval,
-                llextra: if bx.cx().type_has_metadata(field.ty) { self.llextra } else { None },
+                val: PlaceValue {
+                    llval,
+                    llextra: if bx.cx().type_has_metadata(field.ty) {
+                        self.val.llextra
+                    } else {
+                        None
+                    },
+                    align: effective_field_align,
+                },
                 layout: field,
-                align: effective_field_align,
             }
         };
 
@@ -142,7 +172,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         // The type `Foo<Foo<Trait>>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that
         // the `y` field has 16-bit alignment.
 
-        let meta = self.llextra;
+        let meta = self.val.llextra;
 
         let unaligned_offset = bx.cx().const_usize(offset.bytes());
 
@@ -164,9 +194,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         debug!("struct_field_ptr: DST field offset: {:?}", offset);
 
         // Adjust pointer.
-        let ptr = bx.inbounds_ptradd(self.llval, offset);
-
-        PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align }
+        let ptr = bx.inbounds_ptradd(self.val.llval, offset);
+        let val =
+            PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align };
+        PlaceRef { val, layout: field }
     }
 
     /// Obtain the actual discriminant of a value.
@@ -312,10 +343,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 let ptr = self.project_field(bx, tag_field);
                 let to =
                     self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
-                bx.store(
+                bx.store_to_place(
                     bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to),
-                    ptr.llval,
-                    ptr.align,
+                    ptr.val,
                 );
             }
             Variants::Multiple {
@@ -357,14 +387,16 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         };
 
         PlaceRef {
-            llval: bx.inbounds_gep(
-                bx.cx().backend_type(self.layout),
-                self.llval,
-                &[bx.cx().const_usize(0), llindex],
-            ),
-            llextra: None,
+            val: PlaceValue {
+                llval: bx.inbounds_gep(
+                    bx.cx().backend_type(self.layout),
+                    self.val.llval,
+                    &[bx.cx().const_usize(0), llindex],
+                ),
+                llextra: None,
+                align: self.val.align.restrict_for_offset(offset),
+            },
             layout,
-            align: self.align.restrict_for_offset(offset),
         }
     }
 
@@ -389,11 +421,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     }
 
     pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
-        bx.lifetime_start(self.llval, self.layout.size);
+        bx.lifetime_start(self.val.llval, self.layout.size);
     }
 
     pub fn storage_dead<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
-        bx.lifetime_end(self.llval, self.layout.size);
+        bx.lifetime_end(self.val.llval, self.layout.size);
     }
 }
 
@@ -461,8 +493,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                     if subslice.layout.is_unsized() {
                         assert!(from_end, "slice subslices should be `from_end`");
-                        subslice.llextra =
-                            Some(bx.sub(cg_base.llextra.unwrap(), bx.cx().const_usize(from + to)));
+                        subslice.val.llextra = Some(
+                            bx.sub(cg_base.val.llextra.unwrap(), bx.cx().const_usize(from + to)),
+                        );
                     }
 
                     subslice
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index d62f560f11f..6725a6d9e38 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -68,13 +68,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         base::coerce_unsized_into(bx, scratch, dest);
                         scratch.storage_dead(bx);
                     }
-                    OperandValue::Ref(llref, None, align) => {
-                        let source = PlaceRef::new_sized_aligned(llref, operand.layout, align);
+                    OperandValue::Ref(val) => {
+                        if val.llextra.is_some() {
+                            bug!("unsized coercion on an unsized rvalue");
+                        }
+                        let source = PlaceRef { val, layout: operand.layout };
                         base::coerce_unsized_into(bx, source, dest);
                     }
-                    OperandValue::Ref(_, Some(_), _) => {
-                        bug!("unsized coercion on an unsized rvalue");
-                    }
                     OperandValue::ZeroSized => {
                         bug!("unsized coercion on a ZST rvalue");
                     }
@@ -95,20 +95,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
 
                 if let OperandValue::Immediate(v) = cg_elem.val {
-                    let start = dest.llval;
+                    let start = dest.val.llval;
                     let size = bx.const_usize(dest.layout.size.bytes());
 
                     // Use llvm.memset.p0i8.* to initialize all zero arrays
                     if bx.cx().const_to_opt_u128(v, false) == Some(0) {
                         let fill = bx.cx().const_u8(0);
-                        bx.memset(start, fill, size, dest.align, MemFlags::empty());
+                        bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
                         return;
                     }
 
                     // Use llvm.memset.p0i8.* to initialize byte arrays
                     let v = bx.from_immediate(v);
                     if bx.cx().val_ty(v) == bx.cx().type_i8() {
-                        bx.memset(start, v, size, dest.align, MemFlags::empty());
+                        bx.memset(start, v, size, dest.val.align, MemFlags::empty());
                         return;
                     }
                 }
@@ -182,7 +182,10 @@ 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.
-                src.val.store(bx, PlaceRef::new_sized_aligned(dst.llval, src.layout, dst.align));
+                src.val.store(
+                    bx,
+                    PlaceRef::new_sized_aligned(dst.val.llval, src.layout, dst.val.align),
+                );
             }
         }
     }
@@ -217,10 +220,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let cast_kind = self.value_kind(cast);
 
         match operand.val {
-            OperandValue::Ref(ptr, meta, align) => {
-                debug_assert_eq!(meta, None);
+            OperandValue::Ref(source_place_val) => {
+                debug_assert_eq!(source_place_val.llextra, None);
                 debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
-                let fake_place = PlaceRef::new_sized_aligned(ptr, cast, align);
+                let fake_place = PlaceRef { val: source_place_val, layout: cast };
                 Some(bx.load_operand(fake_place).val)
             }
             OperandValue::ZeroSized => {
@@ -375,7 +378,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) {
         debug!(
             "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})",
-            indirect_dest.llval, rvalue
+            indirect_dest.val.llval, rvalue
         );
 
         match *rvalue {
@@ -487,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                     mir::CastKind::DynStar => {
                         let (lldata, llextra) = match operand.val {
-                            OperandValue::Ref(_, _, _) => todo!(),
+                            OperandValue::Ref(..) => todo!(),
                             OperandValue::Immediate(v) => (v, None),
                             OperandValue::Pair(v, l) => (v, Some(l)),
                             OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"),
@@ -765,9 +768,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Note: places are indirect, so storing the `llval` into the
         // destination effectively creates a reference.
         let val = if !bx.cx().type_has_metadata(ty) {
-            OperandValue::Immediate(cg_place.llval)
+            OperandValue::Immediate(cg_place.val.llval)
         } else {
-            OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
+            OperandValue::Pair(cg_place.val.llval, cg_place.val.llextra.unwrap())
         };
         OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) }
     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index c0281e75d9d..9191618c064 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -12,7 +12,7 @@ use crate::common::{
     AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
 use crate::mir::operand::{OperandRef, OperandValue};
-use crate::mir::place::PlaceRef;
+use crate::mir::place::{PlaceRef, PlaceValue};
 use crate::MemFlags;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -156,6 +156,10 @@ pub trait BuilderMethods<'a, 'tcx>:
         order: AtomicOrdering,
         size: Size,
     ) -> Self::Value;
+    fn load_from_place(&mut self, ty: Self::Type, place: PlaceValue<Self::Value>) -> Self::Value {
+        debug_assert_eq!(place.llextra, None);
+        self.load(ty, place.llval, place.align)
+    }
     fn load_operand(&mut self, place: PlaceRef<'tcx, Self::Value>)
     -> OperandRef<'tcx, Self::Value>;
 
@@ -171,6 +175,10 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn nonnull_metadata(&mut self, load: Self::Value);
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
+    fn store_to_place(&mut self, val: Self::Value, place: PlaceValue<Self::Value>) -> Self::Value {
+        debug_assert_eq!(place.llextra, None);
+        self.store(val, place.llval, place.align)
+    }
     fn store_with_flags(
         &mut self,
         val: Self::Value,
@@ -290,14 +298,14 @@ pub trait BuilderMethods<'a, 'tcx>:
         src: PlaceRef<'tcx, Self::Value>,
         flags: MemFlags,
     ) {
-        debug_assert!(src.llextra.is_none(), "cannot directly copy from unsized values");
-        debug_assert!(dst.llextra.is_none(), "cannot directly copy into unsized values");
+        debug_assert!(src.val.llextra.is_none(), "cannot directly copy from unsized values");
+        debug_assert!(dst.val.llextra.is_none(), "cannot directly copy into unsized values");
         debug_assert_eq!(dst.layout.size, src.layout.size);
         if flags.contains(MemFlags::NONTEMPORAL) {
             // HACK(nox): This is inefficient but there is no nontemporal memcpy.
             let ty = self.backend_type(dst.layout);
-            let val = self.load(ty, src.llval, src.align);
-            self.store_with_flags(val, dst.llval, dst.align, flags);
+            let val = self.load_from_place(ty, src.val);
+            self.store_with_flags(val, dst.val.llval, dst.val.align, flags);
         } else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout)
         {
             // If we're not optimizing, the aliasing information from `memcpy`
@@ -306,7 +314,7 @@ pub trait BuilderMethods<'a, 'tcx>:
             temp.val.store_with_flags(self, dst, flags);
         } else if !dst.layout.is_zst() {
             let bytes = self.const_usize(dst.layout.size.bytes());
-            self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags);
+            self.memcpy(dst.val.llval, dst.val.align, src.val.llval, src.val.align, bytes, flags);
         }
     }
 
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index 4a0ed87f77c..4c9acfe0f71 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -1,5 +1,8 @@
 //! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.
 
+// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
+// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
+use rustc_serialize::int_overflow::{DebugStrictAdd, DebugStrictSub};
 use std::hash::Hasher;
 use std::mem::{self, MaybeUninit};
 use std::ptr;
@@ -103,19 +106,19 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize)
         }
 
         let mut i = 0;
-        if i + 3 < count {
+        if i.debug_strict_add(3) < count {
             ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4);
-            i += 4;
+            i = i.debug_strict_add(4);
         }
 
-        if i + 1 < count {
+        if i.debug_strict_add(1) < count {
             ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2);
-            i += 2
+            i = i.debug_strict_add(2)
         }
 
         if i < count {
             *dst.add(i) = *src.add(i);
-            i += 1;
+            i = i.debug_strict_add(1);
         }
 
         debug_assert_eq!(i, count);
@@ -211,14 +214,14 @@ impl SipHasher128 {
         debug_assert!(nbuf < BUFFER_SIZE);
         debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
 
-        if nbuf + LEN < BUFFER_SIZE {
+        if nbuf.debug_strict_add(LEN) < BUFFER_SIZE {
             unsafe {
                 // The memcpy call is optimized away because the size is known.
                 let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
                 ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
             }
 
-            self.nbuf = nbuf + LEN;
+            self.nbuf = nbuf.debug_strict_add(LEN);
 
             return;
         }
@@ -265,8 +268,9 @@ impl SipHasher128 {
             // This function should only be called when the write fills the buffer.
             // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
             // LEN is statically known, so the branch is optimized away.
-            self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
-            self.processed += BUFFER_SIZE;
+            self.nbuf =
+                if LEN == 1 { 0 } else { nbuf.debug_strict_add(LEN).debug_strict_sub(BUFFER_SIZE) };
+            self.processed = self.processed.debug_strict_add(BUFFER_SIZE);
         }
     }
 
@@ -277,7 +281,7 @@ impl SipHasher128 {
         let nbuf = self.nbuf;
         debug_assert!(nbuf < BUFFER_SIZE);
 
-        if nbuf + length < BUFFER_SIZE {
+        if nbuf.debug_strict_add(length) < BUFFER_SIZE {
             unsafe {
                 let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
 
@@ -289,7 +293,7 @@ impl SipHasher128 {
                 }
             }
 
-            self.nbuf = nbuf + length;
+            self.nbuf = nbuf.debug_strict_add(length);
 
             return;
         }
@@ -315,7 +319,7 @@ impl SipHasher128 {
             // This function should only be called when the write fills the buffer,
             // so we know that there is enough input to fill the current element.
             let valid_in_elem = nbuf % ELEM_SIZE;
-            let needed_in_elem = ELEM_SIZE - valid_in_elem;
+            let needed_in_elem = ELEM_SIZE.debug_strict_sub(valid_in_elem);
 
             let src = msg.as_ptr();
             let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
@@ -327,7 +331,7 @@ impl SipHasher128 {
             // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0.
             // We know that is true, because last step ensured we have a full
             // element in the buffer.
-            let last = nbuf / ELEM_SIZE + 1;
+            let last = (nbuf / ELEM_SIZE).debug_strict_add(1);
 
             for i in 0..last {
                 let elem = self.buf.get_unchecked(i).assume_init().to_le();
@@ -338,7 +342,7 @@ impl SipHasher128 {
 
             // Process the remaining element-sized chunks of input.
             let mut processed = needed_in_elem;
-            let input_left = length - processed;
+            let input_left = length.debug_strict_sub(processed);
             let elems_left = input_left / ELEM_SIZE;
             let extra_bytes_left = input_left % ELEM_SIZE;
 
@@ -347,7 +351,7 @@ impl SipHasher128 {
                 self.state.v3 ^= elem;
                 Sip13Rounds::c_rounds(&mut self.state);
                 self.state.v0 ^= elem;
-                processed += ELEM_SIZE;
+                processed = processed.debug_strict_add(ELEM_SIZE);
             }
 
             // Copy remaining input into start of buffer.
@@ -356,7 +360,7 @@ impl SipHasher128 {
             copy_nonoverlapping_small(src, dst, extra_bytes_left);
 
             self.nbuf = extra_bytes_left;
-            self.processed += nbuf + processed;
+            self.processed = self.processed.debug_strict_add(nbuf.debug_strict_add(processed));
         }
     }
 
@@ -394,7 +398,7 @@ impl SipHasher128 {
         };
 
         // Finalize the hash.
-        let length = self.processed + self.nbuf;
+        let length = self.processed.debug_strict_add(self.nbuf);
         let b: u64 = ((length as u64 & 0xff) << 56) | elem;
 
         state.v3 ^= b;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index e4fb13822f8..a8bba3afb7e 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-ctrlc = "3.4.4"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
@@ -66,6 +65,11 @@ features = [
     "Win32_System_Diagnostics_Debug",
 ]
 
+[target.'cfg(not(target_family = "wasm"))'.dependencies]
+# tidy-alphabetical-start
+ctrlc = "3.4.4"
+# tidy-alphabetical-end
+
 [features]
 # tidy-alphabetical-start
 llvm = ['rustc_interface/llvm']
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 1f44621736c..b3cba4dbfc2 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1500,6 +1500,7 @@ pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) {
 /// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`].
 /// Making this handler optional lets tools can install a different handler, if they wish.
 pub fn install_ctrlc_handler() {
+    #[cfg(not(target_family = "wasm"))]
     ctrlc::set_handler(move || {
         // Indicate that we have been signaled to stop. If we were already signaled, exit
         // immediately. In our interpreter loop we try to consult this value often, but if for
diff --git a/compiler/rustc_error_codes/src/error_codes/E0384.md b/compiler/rustc_error_codes/src/error_codes/E0384.md
index e21fac0797c..6680dbed3dd 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0384.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0384.md
@@ -18,3 +18,16 @@ fn main() {
     x = 5;
 }
 ```
+
+Alternatively, you might consider initializing a new variable: either with a new
+bound name or (by [shadowing]) with the bound name of your existing variable.
+For example:
+
+[shadowing]: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
+
+```
+fn main() {
+    let x = 3;
+    let x = 5;
+}
+```
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index bd8e78bda26..6ce3fa3535d 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1513,7 +1513,9 @@ impl HumanEmitter {
                 for line_idx in 0..annotated_file.lines.len() {
                     let file = annotated_file.file.clone();
                     let line = &annotated_file.lines[line_idx];
-                    if let Some(source_string) = file.get_line(line.line_index - 1) {
+                    if let Some(source_string) =
+                        line.line_index.checked_sub(1).and_then(|l| file.get_line(l))
+                    {
                         let leading_whitespace = source_string
                             .chars()
                             .take_while(|c| c.is_whitespace())
@@ -1553,7 +1555,10 @@ impl HumanEmitter {
                 for line in &annotated_file.lines {
                     max_line_len = max(
                         max_line_len,
-                        annotated_file.file.get_line(line.line_index - 1).map_or(0, |s| s.len()),
+                        line.line_index
+                            .checked_sub(1)
+                            .and_then(|l| annotated_file.file.get_line(l))
+                            .map_or(0, |s| s.len()),
                     );
                     for ann in &line.annotations {
                         span_right_margin = max(span_right_margin, ann.start_col.display);
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index db94e0b08bc..4f62323231a 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1082,7 +1082,7 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
 /// This means it can be used cross crate.
 pub fn encode_cross_crate(name: Symbol) -> bool {
     if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) {
-        if attr.encode_cross_crate == EncodeCrossCrate::Yes { true } else { false }
+        attr.encode_cross_crate == EncodeCrossCrate::Yes
     } else {
         true
     }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 8d4ae10d4bf..216b89fd4f1 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -22,7 +22,6 @@ use rustc_middle::ty::{
     AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
-use rustc_span::symbol::sym;
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -506,7 +505,6 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 }
 
 pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let _indenter = indenter();
     match tcx.def_kind(def_id) {
         DefKind::Static { .. } => {
             tcx.ensure().typeck(def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 1958a80d47c..45ccd0fa2e0 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -143,7 +143,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                 };
                 assert!(
                     ty.is_manually_drop(),
-                    "expected first field of `MaybeUnit` to be `ManuallyDrop`"
+                    "expected first field of `MaybeUninit` to be `ManuallyDrop`"
                 );
                 let fields = &ty.non_enum_variant().fields;
                 let ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 8760901b71b..024a0433b8c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -81,6 +81,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{pluralize, struct_span_code_err, Diag};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::Mutability;
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -91,17 +92,17 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::errors;
 use crate::require_c_abi_if_c_variadic;
-use crate::util::common::indenter;
 
 use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
 use self::region::region_scope_tree;
@@ -466,14 +467,64 @@ fn fn_sig_suggestion<'tcx>(
     )
 }
 
-pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+pub fn ty_kind_suggestion<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<String> {
+    // Keep in sync with `rustc_borrowck/src/diagnostics/conflict_errors.rs:ty_kind_suggestion`.
+    // FIXME: deduplicate the above.
+    let implements_default = |ty| {
+        let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+            return false;
+        };
+        let infcx = tcx.infer_ctxt().build();
+        infcx
+            .type_implements_trait(default_trait, [ty], ty::ParamEnv::reveal_all())
+            .must_apply_modulo_regions()
+    };
     Some(match ty.kind() {
-        ty::Bool => "true",
-        ty::Char => "'a'",
-        ty::Int(_) | ty::Uint(_) => "42",
-        ty::Float(_) => "3.14159",
-        ty::Error(_) | ty::Never => return None,
-        _ => "value",
+        ty::Never | ty::Error(_) => return None,
+        ty::Bool => "false".to_string(),
+        ty::Char => "\'x\'".to_string(),
+        ty::Int(_) | ty::Uint(_) => "42".into(),
+        ty::Float(_) => "3.14159".into(),
+        ty::Slice(_) => "[]".to_string(),
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
+            "vec![]".to_string()
+        }
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
+            "String::new()".to_string()
+        }
+        ty::Adt(def, args) if def.is_box() => {
+            format!("Box::new({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
+        }
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
+            "None".to_string()
+        }
+        ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
+            format!("Ok({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
+        }
+        ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
+        ty::Ref(_, ty, mutability) => {
+            if let (ty::Str, Mutability::Not) = (ty.kind(), mutability) {
+                "\"\"".to_string()
+            } else {
+                let Some(ty) = ty_kind_suggestion(*ty, tcx) else {
+                    return None;
+                };
+                format!("&{}{ty}", mutability.prefix_str())
+            }
+        }
+        ty::Array(ty, len) => format!(
+            "[{}; {}]",
+            ty_kind_suggestion(*ty, tcx)?,
+            len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
+        ),
+        ty::Tuple(tys) => format!(
+            "({})",
+            tys.iter()
+                .map(|ty| ty_kind_suggestion(ty, tcx))
+                .collect::<Option<Vec<String>>>()?
+                .join(", ")
+        ),
+        _ => "value".to_string(),
     })
 }
 
@@ -511,7 +562,7 @@ fn suggestion_signature<'tcx>(
         }
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id).instantiate_identity();
-            let val = ty_kind_suggestion(ty).unwrap_or("todo!()");
+            let val = ty_kind_suggestion(ty, tcx).unwrap_or_else(|| "value".to_string());
             format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index a705d3bc107..c1bf65367aa 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -30,7 +30,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
 use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -1383,7 +1383,9 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                     Applicability::MachineApplicable,
                 );
                 should_recover = true;
-            } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
+            } else if let Some(sugg) =
+                suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
+            {
                 diag.span_suggestion(
                     ty.span,
                     "replace with an appropriate return type",
@@ -1426,11 +1428,10 @@ fn infer_return_ty_for_fn_sig<'tcx>(
     }
 }
 
-fn suggest_impl_trait<'tcx>(
-    tcx: TyCtxt<'tcx>,
+pub fn suggest_impl_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     ret_ty: Ty<'tcx>,
-    span: Span,
-    def_id: LocalDefId,
 ) -> Option<String> {
     let format_as_assoc: fn(_, _, _, _, _) -> _ =
         |tcx: TyCtxt<'tcx>,
@@ -1464,24 +1465,28 @@ fn suggest_impl_trait<'tcx>(
 
     for (trait_def_id, assoc_item_def_id, formatter) in [
         (
-            tcx.get_diagnostic_item(sym::Iterator),
-            tcx.get_diagnostic_item(sym::IteratorItem),
+            infcx.tcx.get_diagnostic_item(sym::Iterator),
+            infcx.tcx.get_diagnostic_item(sym::IteratorItem),
             format_as_assoc,
         ),
         (
-            tcx.lang_items().future_trait(),
-            tcx.get_diagnostic_item(sym::FutureOutput),
+            infcx.tcx.lang_items().future_trait(),
+            infcx.tcx.get_diagnostic_item(sym::FutureOutput),
             format_as_assoc,
         ),
-        (tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
         (
-            tcx.lang_items().fn_mut_trait(),
-            tcx.lang_items().fn_once_output(),
+            infcx.tcx.lang_items().fn_trait(),
+            infcx.tcx.lang_items().fn_once_output(),
+            format_as_parenthesized,
+        ),
+        (
+            infcx.tcx.lang_items().fn_mut_trait(),
+            infcx.tcx.lang_items().fn_once_output(),
             format_as_parenthesized,
         ),
         (
-            tcx.lang_items().fn_once_trait(),
-            tcx.lang_items().fn_once_output(),
+            infcx.tcx.lang_items().fn_once_trait(),
+            infcx.tcx.lang_items().fn_once_output(),
             format_as_parenthesized,
         ),
     ] {
@@ -1491,36 +1496,45 @@ fn suggest_impl_trait<'tcx>(
         let Some(assoc_item_def_id) = assoc_item_def_id else {
             continue;
         };
-        if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
+        if infcx.tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
             continue;
         }
-        let param_env = tcx.param_env(def_id);
-        let infcx = tcx.infer_ctxt().build();
-        let args = ty::GenericArgs::for_item(tcx, trait_def_id, |param, _| {
-            if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
+        let sugg = infcx.probe(|_| {
+            let args = ty::GenericArgs::for_item(infcx.tcx, trait_def_id, |param, _| {
+                if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(DUMMY_SP, param) }
+            });
+            if !infcx
+                .type_implements_trait(trait_def_id, args, param_env)
+                .must_apply_modulo_regions()
+            {
+                return None;
+            }
+            let ocx = ObligationCtxt::new(&infcx);
+            let item_ty = ocx.normalize(
+                &ObligationCause::dummy(),
+                param_env,
+                Ty::new_projection(infcx.tcx, assoc_item_def_id, args),
+            );
+            // FIXME(compiler-errors): We may benefit from resolving regions here.
+            if ocx.select_where_possible().is_empty()
+                && let item_ty = infcx.resolve_vars_if_possible(item_ty)
+                && let Some(item_ty) = item_ty.make_suggestable(infcx.tcx, false, None)
+                && let Some(sugg) = formatter(
+                    infcx.tcx,
+                    infcx.resolve_vars_if_possible(args),
+                    trait_def_id,
+                    assoc_item_def_id,
+                    item_ty,
+                )
+            {
+                return Some(sugg);
+            }
+
+            None
         });
-        if !infcx.type_implements_trait(trait_def_id, args, param_env).must_apply_modulo_regions() {
-            continue;
-        }
-        let ocx = ObligationCtxt::new(&infcx);
-        let item_ty = ocx.normalize(
-            &ObligationCause::misc(span, def_id),
-            param_env,
-            Ty::new_projection(tcx, assoc_item_def_id, args),
-        );
-        // FIXME(compiler-errors): We may benefit from resolving regions here.
-        if ocx.select_where_possible().is_empty()
-            && let item_ty = infcx.resolve_vars_if_possible(item_ty)
-            && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
-            && let Some(sugg) = formatter(
-                tcx,
-                infcx.resolve_vars_if_possible(args),
-                trait_def_id,
-                assoc_item_def_id,
-                item_ty,
-            )
-        {
-            return Some(sugg);
+
+        if sugg.is_some() {
+            return sugg;
         }
     }
     None
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index affd678fc6c..3d16f1420d9 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -718,6 +718,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::Pat<'tcx>) {
+        intravisit::walk_pat(self, p)
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 70f09dd6175..822bf95305f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1134,7 +1134,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         for (what, span) in types_and_spans {
             err.span_label(span, format!("not allowed on {what}"));
         }
-        generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
+        generics_args_err_extend(self.tcx(), segments, &mut err, err_extend);
         let reported = err.emit();
         self.set_tainted_by_errors(reported);
         reported
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 9fb8b4ac40e..63aeb165a48 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2234,11 +2234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                         .type_of(def_id)
                                         .no_bound_vars()
                                         .expect("const parameter types cannot be generic");
-                                    let item_def_id = tcx.parent(def_id);
-                                    let generics = tcx.generics_of(item_def_id);
-                                    let index = generics.param_def_id_to_index[&def_id];
-                                    let name = tcx.item_name(def_id);
-                                    ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty)
+                                    self.lower_const_param(expr.hir_id, ty)
                                 }
 
                                 _ => {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 5a374fa5e04..c374f9762d6 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -103,7 +103,6 @@ use rustc_middle::middle;
 use rustc_middle::mir::interpret::GlobalId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::util;
 use rustc_session::parse::feature_err;
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index a590c648d20..39312614c1b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1142,7 +1142,7 @@ impl<'a> State<'a> {
     }
 
     fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
-        let assoc_op = bin_op_to_assoc_op(op.node);
+        let assoc_op = AssocOp::from_ast_binop(op.node);
         let prec = assoc_op.precedence() as i8;
         let fixity = assoc_op.fixity();
 
@@ -2328,33 +2328,6 @@ fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
     }
 }
 
-fn bin_op_to_assoc_op(op: hir::BinOpKind) -> AssocOp {
-    use crate::hir::BinOpKind::*;
-    match op {
-        Add => AssocOp::Add,
-        Sub => AssocOp::Subtract,
-        Mul => AssocOp::Multiply,
-        Div => AssocOp::Divide,
-        Rem => AssocOp::Modulus,
-
-        And => AssocOp::LAnd,
-        Or => AssocOp::LOr,
-
-        BitXor => AssocOp::BitXor,
-        BitAnd => AssocOp::BitAnd,
-        BitOr => AssocOp::BitOr,
-        Shl => AssocOp::ShiftLeft,
-        Shr => AssocOp::ShiftRight,
-
-        Eq => AssocOp::Equal,
-        Lt => AssocOp::Less,
-        Le => AssocOp::LessEqual,
-        Ne => AssocOp::NotEqual,
-        Ge => AssocOp::GreaterEqual,
-        Gt => AssocOp::Greater,
-    }
-}
-
 /// Expressions that syntactically contain an "exterior" struct literal, i.e., not surrounded by any
 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 51d01afc4eb..720f4927ea8 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -2004,16 +2004,17 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             }
         }
 
-        let parent_id = fcx.tcx.hir().get_parent_item(id);
-        let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id);
+        let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id;
+        let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
         // When suggesting return, we need to account for closures and async blocks, not just items.
         for (_, node) in fcx.tcx.hir().parent_iter(id) {
             match node {
                 hir::Node::Expr(&hir::Expr {
-                    kind: hir::ExprKind::Closure(hir::Closure { .. }),
+                    kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
                     ..
                 }) => {
                     parent_item = node;
+                    parent_id = *def_id;
                     break;
                 }
                 hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
@@ -2023,13 +2024,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
 
         if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
             fcx.suggest_missing_break_or_return_expr(
-                &mut err,
-                expr,
-                fn_decl,
-                expected,
-                found,
-                id,
-                parent_id.into(),
+                &mut err, expr, fn_decl, expected, found, id, parent_id,
             );
         }
 
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7a1a2c498aa..8f30c3fd377 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -694,10 +694,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                             let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
                             self.annotate_loop_expected_due_to_inference(err, expr, error);
-                            if let Some(val) = ty_kind_suggestion(ty) {
+                            if let Some(val) = ty_kind_suggestion(ty, tcx) {
                                 err.span_suggestion_verbose(
                                     expr.span.shrink_to_hi(),
-                                    "give it a value of the expected type",
+                                    "give the `break` a value of the expected type",
                                     format!(" {val}"),
                                     Applicability::HasPlaceholders,
                                 );
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index f1e82543a99..2580179ce5b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -561,9 +561,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Unify `interior` with `witness` and collect all the resulting obligations.
             let span = self.tcx.hir().body(body_id).value.span;
+            let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
+                span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
+            };
             let ok = self
                 .at(&self.misc(span), self.param_env)
-                .eq(DefineOpaqueTypes::No, interior, witness)
+                // Will never define opaque types, as all we do is instantiate a type variable.
+                .eq(DefineOpaqueTypes::Yes, interior, witness)
                 .expect("Failed to unify coroutine interior type");
             let mut obligations = ok.obligations;
 
@@ -942,7 +946,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn get_node_fn_decl(
         &self,
         node: Node<'tcx>,
-    ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
         match node {
             Node::Item(&hir::Item {
                 ident,
@@ -953,25 +957,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // This is less than ideal, it will not suggest a return type span on any
                 // method called `main`, regardless of whether it is actually the entry point,
                 // but it will still present it as the reason for the expected type.
-                Some((
-                    hir::HirId::make_owner(owner_id.def_id),
-                    &sig.decl,
-                    ident,
-                    ident.name != sym::main,
-                ))
+                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
             }
             Node::TraitItem(&hir::TraitItem {
                 ident,
                 kind: hir::TraitItemKind::Fn(ref sig, ..),
                 owner_id,
                 ..
-            }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
+            }) => Some((owner_id.def_id, &sig.decl, ident, true)),
             Node::ImplItem(&hir::ImplItem {
                 ident,
                 kind: hir::ImplItemKind::Fn(ref sig, ..),
                 owner_id,
                 ..
-            }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
+            }) => Some((owner_id.def_id, &sig.decl, ident, false)),
             Node::Expr(&hir::Expr {
                 hir_id,
                 kind:
@@ -1001,12 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }) => (ident, sig, owner_id),
                     _ => return None,
                 };
-                Some((
-                    hir::HirId::make_owner(owner_id.def_id),
-                    &sig.decl,
-                    ident,
-                    ident.name != sym::main,
-                ))
+                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
             }
             _ => None,
         }
@@ -1017,7 +1011,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn get_fn_decl(
         &self,
         blk_id: hir::HirId,
-    ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
+    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
         self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 442bfd75746..ce203eae95f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -9,6 +9,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use crate::rustc_middle::ty::Article;
 use core::cmp::min;
 use core::iter;
+use hir::def_id::LocalDefId;
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::{Applicability, Diag, MultiSpan};
@@ -20,6 +21,7 @@ use rustc_hir::{
     CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
     Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
+use rustc_hir_analysis::collect::suggest_impl_trait;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::traits::{self};
 use rustc_middle::lint::in_external_macro;
@@ -795,7 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         can_suggest: bool,
-        fn_id: hir::HirId,
+        fn_id: LocalDefId,
     ) -> bool {
         let found =
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
@@ -814,17 +816,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
                     );
                     return true;
-                } else if let ty::Closure(_, args) = found.kind()
-                    // FIXME(compiler-errors): Get better at printing binders...
-                    && let closure = args.as_closure()
-                    && closure.sig().is_suggestable(self.tcx, false)
-                {
+                } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
                     err.subdiagnostic(
                         self.dcx(),
-                        errors::AddReturnTypeSuggestion::Add {
-                            span,
-                            found: closure.print_as_impl_trait().to_string(),
-                        },
+                        errors::AddReturnTypeSuggestion::Add { span, found: sugg },
                     );
                     return true;
                 } else {
@@ -929,7 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut Diag<'_>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-        fn_id: hir::HirId,
+        fn_id: LocalDefId,
     ) {
         // Only apply the suggestion if:
         //  - the return type is a generic parameter
@@ -943,7 +938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let ty::Param(expected_ty_as_param) = expected.kind() else { return };
 
-        let fn_node = self.tcx.hir_node(fn_id);
+        let fn_node = self.tcx.hir_node_by_def_id(fn_id);
 
         let hir::Node::Item(hir::Item {
             kind:
@@ -1037,7 +1032,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         id: hir::HirId,
-        fn_id: hir::HirId,
+        fn_id: LocalDefId,
     ) {
         if !expected.is_unit() {
             return;
@@ -1089,11 +1084,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let can_return = match fn_decl.output {
             hir::FnRetTy::Return(ty) => {
                 let ty = self.lowerer().lower_ty(ty);
-                let bound_vars = self.tcx.late_bound_vars(fn_id);
+                let bound_vars = self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
                 let ty = self
                     .tcx
                     .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
-                let ty = match self.tcx.asyncness(fn_id.owner) {
+                let ty = match self.tcx.asyncness(fn_id) {
                     ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
                         span_bug!(
                             fn_decl.output.span(),
@@ -1114,8 +1109,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => false,
         };
         if can_return
-            && let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner()
-            && let Some(span) = expr.span.find_ancestor_inside(*owner_node.span())
+            && let Some(span) = expr.span.find_ancestor_inside(
+                self.tcx.hir().span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)),
+            )
         {
             err.multipart_suggestion(
                 "you might have meant to return this value",
@@ -1291,12 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
             ))
         {
-            let mut span = expr.span;
-            while expr.span.eq_ctxt(span)
-                && let Some(parent_callsite) = span.parent_callsite()
-            {
-                span = parent_callsite;
-            }
+            let span = expr.span.find_oldest_ancestor_in_same_ctxt();
 
             let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
                 vec![(span.shrink_to_hi(), ".into()".to_owned())]
@@ -1901,12 +1892,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => sugg.to_string(),
         };
 
-        err.span_suggestion_verbose(
-            expr.span.shrink_to_hi(),
-            msg,
-            sugg,
-            Applicability::HasPlaceholders,
-        );
+        let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+        err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
         return true;
     }
 
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 700dde184f2..476df9ae793 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -56,7 +56,7 @@ use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{Map, Visitor};
 use rustc_hir::{HirIdMap, Node};
 use rustc_hir_analysis::check::check_abi;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@@ -436,6 +436,28 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
     diag.emit()
 }
 
+pub fn lookup_method_for_diagnostic<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (def_id, hir_id): (LocalDefId, hir::HirId),
+) -> Option<DefId> {
+    let root_ctxt = TypeckRootCtxt::new(tcx, def_id);
+    let param_env = tcx.param_env(def_id);
+    let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, def_id);
+    let hir::Node::Expr(expr) = tcx.hir().hir_node(hir_id) else {
+        return None;
+    };
+    let hir::ExprKind::MethodCall(segment, rcvr, _, _) = expr.kind else {
+        return None;
+    };
+    let tables = tcx.typeck(def_id);
+    // The found `Self` type of the method call.
+    let possible_rcvr_ty = tables.node_type_opt(rcvr.hir_id)?;
+    fn_ctxt
+        .lookup_method_for_diagnostic(possible_rcvr_ty, segment, expr.span, expr, rcvr)
+        .ok()
+        .map(|method| method.def_id)
+}
+
 pub fn provide(providers: &mut Providers) {
     method::provide(providers);
     *providers = Providers {
@@ -443,6 +465,7 @@ pub fn provide(providers: &mut Providers) {
         diagnostic_only_typeck,
         has_typeck_results,
         used_trait_imports,
+        lookup_method_for_diagnostic: lookup_method_for_diagnostic,
         ..*providers
     };
 }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index a199f57aad9..754866c85c4 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -529,16 +529,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MachineApplicable,
             );
         }
-        if let ty::RawPtr(_, _) = &rcvr_ty.kind() {
-            err.note(
-                "try using `<*const T>::as_ref()` to get a reference to the \
-                 type behind the pointer: https://doc.rust-lang.org/std/\
-                 primitive.pointer.html#method.as_ref",
-            );
-            err.note(
-                "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
-                 to invalid or uninitialized memory is undefined behavior",
+
+        // on pointers, check if the method would exist on a reference
+        if let SelfSource::MethodCall(rcvr_expr) = source
+            && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind()
+            && let Ok(pick) = self.lookup_probe_for_diagnostic(
+                item_name,
+                Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl),
+                self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
+                ProbeScope::TraitsInScope,
+                None,
+            )
+            && let ty::Ref(_, _, sugg_mutbl) = *pick.self_ty.kind()
+            && (sugg_mutbl.is_not() || ptr_mutbl.is_mut())
+        {
+            let (method, method_anchor) = match sugg_mutbl {
+                Mutability::Not => {
+                    let method_anchor = match ptr_mutbl {
+                        Mutability::Not => "as_ref",
+                        Mutability::Mut => "as_ref-1",
+                    };
+                    ("as_ref", method_anchor)
+                }
+                Mutability::Mut => ("as_mut", "as_mut"),
+            };
+            err.span_note(
+                tcx.def_span(pick.item.def_id),
+                format!("the method `{item_name}` exists on the type `{ty}`", ty = pick.self_ty),
             );
+            let mut_str = ptr_mutbl.ptr_str();
+            err.note(format!(
+                "you might want to use the unsafe method `<*{mut_str} T>::{method}` to get \
+                an optional reference to the value behind the pointer"
+            ));
+            err.note(format!(
+                "read the documentation for `<*{mut_str} T>::{method}` and ensure you satisfy its \
+                safety preconditions before calling it to avoid undefined behavior: \
+                https://doc.rust-lang.org/std/primitive.pointer.html#method.{method_anchor}"
+            ));
         }
 
         let mut ty_span = match rcvr_ty.kind() {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index b17b312a797..94b723f694e 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -382,11 +382,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         (err, output_def_id)
                     }
                 };
-                if self.check_for_missing_semi(expr, &mut err)
-                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id)
-                    && let hir::ExprKind::Assign(..) = expr.kind
+
+                // Try to suggest a semicolon if it's `A \n *B` where `B` is a place expr
+                let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err);
+
+                // We defer to the later error produced by `check_lhs_assignable`.
+                // We only downgrade this if it's the LHS, though.
+                if maybe_missing_semi
+                    && let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id)
+                    && let hir::ExprKind::Assign(lhs, _, _) = parent.kind
+                    && lhs.hir_id == expr.hir_id
                 {
-                    // We defer to the later error produced by `check_lhs_assignable`.
                     err.downgrade_to_delayed_bug();
                 }
 
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index c987bfb9a0e..86f36eedd90 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -43,7 +43,8 @@ use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, Pro
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{
-    self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
+    self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs,
+    UpvarCapture,
 };
 use rustc_session::lint;
 use rustc_span::sym;
@@ -191,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
             }
         };
+        let args = self.resolve_vars_if_possible(args);
         let closure_def_id = closure_def_id.expect_local();
 
         assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
@@ -361,43 +363,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // For coroutine-closures, we additionally must compute the
         // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref
         // version of the coroutine-closure's output coroutine.
-        if let UpvarArgs::CoroutineClosure(args) = args {
+        if let UpvarArgs::CoroutineClosure(args) = args
+            && !args.references_error()
+        {
             let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
                 self.tcx,
                 ty::INNERMOST,
                 ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv },
             );
+
+            let num_args = args
+                .as_coroutine_closure()
+                .coroutine_closure_sig()
+                .skip_binder()
+                .tupled_inputs_ty
+                .tuple_fields()
+                .len();
+            let typeck_results = self.typeck_results.borrow();
+
             let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter(
                 self.tcx,
-                self.typeck_results
-                    .borrow()
-                    .closure_min_captures_flattened(
-                        self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
-                    )
-                    // Skip the captures that are just moving the closure's args
-                    // into the coroutine. These are always by move, and we append
-                    // those later in the `CoroutineClosureSignature` helper functions.
-                    .skip(
-                        args.as_coroutine_closure()
-                            .coroutine_closure_sig()
-                            .skip_binder()
-                            .tupled_inputs_ty
-                            .tuple_fields()
-                            .len(),
-                    )
-                    .map(|captured_place| {
-                        let upvar_ty = captured_place.place.ty();
-                        let capture = captured_place.info.capture_kind;
+                ty::analyze_coroutine_closure_captures(
+                    typeck_results.closure_min_captures_flattened(closure_def_id),
+                    typeck_results
+                        .closure_min_captures_flattened(
+                            self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
+                        )
+                        // Skip the captures that are just moving the closure's args
+                        // into the coroutine. These are always by move, and we append
+                        // those later in the `CoroutineClosureSignature` helper functions.
+                        .skip(num_args),
+                    |(_, parent_capture), (_, child_capture)| {
+                        // This is subtle. See documentation on function.
+                        let needs_ref = should_reborrow_from_env_of_parent_coroutine_closure(
+                            parent_capture,
+                            child_capture,
+                        );
+
+                        let upvar_ty = child_capture.place.ty();
+                        let capture = child_capture.info.capture_kind;
                         // Not all upvars are captured by ref, so use
                         // `apply_capture_kind_on_capture_ty` to ensure that we
                         // compute the right captured type.
-                        apply_capture_kind_on_capture_ty(
+                        return apply_capture_kind_on_capture_ty(
                             self.tcx,
                             upvar_ty,
                             capture,
-                            Some(closure_env_region),
-                        )
-                    }),
+                            if needs_ref { Some(closure_env_region) } else { child_capture.region },
+                        );
+                    },
+                ),
             );
             let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
                 self.tcx,
@@ -1761,6 +1776,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
+/// Determines whether a child capture that is derived from a parent capture
+/// should be borrowed with the lifetime of the parent coroutine-closure's env.
+///
+/// There are two cases when this needs to happen:
+///
+/// (1.) Are we borrowing data owned by the parent closure? We can determine if
+/// that is the case by checking if the parent capture is by move, EXCEPT if we
+/// apply a deref projection, which means we're reborrowing a reference that we
+/// captured by move.
+///
+/// ```rust
+/// #![feature(async_closure)]
+/// let x = &1i32; // Let's call this lifetime `'1`.
+/// let c = async move || {
+///     println!("{:?}", *x);
+///     // Even though the inner coroutine borrows by ref, we're only capturing `*x`,
+///     // not `x`, so the inner closure is allowed to reborrow the data for `'1`.
+/// };
+/// ```
+///
+/// (2.) If a coroutine is mutably borrowing from a parent capture, then that
+/// mutable borrow cannot live for longer than either the parent *or* the borrow
+/// that we have on the original upvar. Therefore we always need to borrow the
+/// child capture with the lifetime of the parent coroutine-closure's env.
+///
+/// ```rust
+/// #![feature(async_closure)]
+/// let mut x = 1i32;
+/// let c = async || {
+///     x = 1;
+///     // The parent borrows `x` for some `&'1 mut i32`.
+///     // However, when we call `c()`, we implicitly autoref for the signature of
+///     // `AsyncFnMut::async_call_mut`. Let's call that lifetime `'call`. Since
+///     // the maximum that `&'call mut &'1 mut i32` can be reborrowed is `&'call mut i32`,
+///     // the inner coroutine should capture w/ the lifetime of the coroutine-closure.
+/// };
+/// ```
+///
+/// If either of these cases apply, then we should capture the borrow with the
+/// lifetime of the parent coroutine-closure's env. Luckily, if this function is
+/// not correct, then the program is not unsound, since we still borrowck and validate
+/// the choices made from this function -- the only side-effect is that the user
+/// may receive unnecessary borrowck errors.
+fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
+    parent_capture: &ty::CapturedPlace<'tcx>,
+    child_capture: &ty::CapturedPlace<'tcx>,
+) -> bool {
+    // (1.)
+    (!parent_capture.is_by_ref()
+        && !matches!(
+            child_capture.place.projections.get(parent_capture.place.projections.len()),
+            Some(Projection { kind: ProjectionKind::Deref, .. })
+        ))
+        // (2.)
+        || matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::MutBorrow))
+}
+
 /// Truncate the capture so that the place being borrowed is in accordance with RFC 1240,
 /// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
 fn restrict_repr_packed_field_ref_capture<'tcx>(
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index fdb6ab8f59b..64f52ea7ac1 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -144,6 +144,9 @@ infer_fps_items_are_distinct = fn items are distinct from fn pointers
 infer_fps_remove_ref = consider removing the reference
 infer_fps_use_ref = consider using a reference
 infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
+
+infer_full_type_written = the full type name has been written to '{$path}'
+
 infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
 infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
 infer_label_bad = {$bad_kind ->
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 6192eaf3c3a..4593108edac 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -18,6 +18,8 @@ use crate::infer::error_reporting::{
     ObligationCauseAsDiagArg,
 };
 
+use std::path::PathBuf;
+
 pub mod note_and_explain;
 
 #[derive(Diagnostic)]
@@ -47,6 +49,9 @@ pub struct AnnotationRequired<'a> {
     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
     #[subdiagnostic]
     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(infer_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
 }
 
 // Copy of `AnnotationRequired` for E0283
@@ -65,6 +70,9 @@ pub struct AmbiguousImpl<'a> {
     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
     #[subdiagnostic]
     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(infer_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
 }
 
 // Copy of `AnnotationRequired` for E0284
@@ -83,6 +91,9 @@ pub struct AmbiguousReturn<'a> {
     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
     #[subdiagnostic]
     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(infer_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
 }
 
 // Used when a better one isn't available
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 f89ed256a08..3b5658ed0ee 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
@@ -18,13 +18,15 @@ use rustc_middle::infer::unify_key::{
 };
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::{self, InferConst};
-use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
-use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
+use rustc_middle::ty::{
+    self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Ty, TyCtxt,
+    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults,
+};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::iter;
+use std::path::PathBuf;
 
 pub enum TypeAnnotationNeeded {
     /// ```compile_fail,E0282
@@ -153,6 +155,29 @@ impl UnderspecifiedArgKind {
     }
 }
 
+struct ClosureEraser<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match ty.kind() {
+            ty::Closure(_, args) => {
+                let closure_sig = args.as_closure().sig();
+                Ty::new_fn_ptr(
+                    self.tcx,
+                    self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal),
+                )
+            }
+            _ => ty.super_fold_with(self),
+        }
+    }
+}
+
 fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
     let mut printer = FmtPrinter::new(infcx.tcx, ns);
     let ty_getter = move |ty_vid| {
@@ -209,6 +234,10 @@ fn ty_to_string<'tcx>(
 ) -> String {
     let mut printer = fmt_printer(infcx, Namespace::TypeNS);
     let ty = infcx.resolve_vars_if_possible(ty);
+    // We use `fn` ptr syntax for closures, but this only works when the closure
+    // does not capture anything.
+    let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx });
+
     match (ty.kind(), called_method_def_id) {
         // We don't want the regular output for `fn`s because it includes its path in
         // invalid pseudo-syntax, we want the `fn`-pointer output instead.
@@ -223,11 +252,6 @@ fn ty_to_string<'tcx>(
             "Vec<_>".to_string()
         }
         _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(),
-        // FIXME: The same thing for closures, but this only works when the closure
-        // does not capture anything.
-        //
-        // We do have to hide the `extern "rust-call"` ABI in that case though,
-        // which is too much of a bother for now.
         _ => {
             ty.print(&mut printer).unwrap();
             printer.into_buffer()
@@ -387,6 +411,8 @@ impl<'tcx> InferCtxt<'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label,
+                was_written: None,
+                path: Default::default(),
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -396,6 +422,8 @@ impl<'tcx> InferCtxt<'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label,
+                was_written: None,
+                path: Default::default(),
             }),
             TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn {
                 span,
@@ -405,6 +433,8 @@ impl<'tcx> InferCtxt<'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label,
+                was_written: None,
+                path: Default::default(),
             }),
         }
     }
@@ -442,7 +472,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
-        let (source_kind, name) = kind.ty_localized_msg(self);
+        let (source_kind, name, path) = kind.ty_localized_msg(self);
         let failure_span = if should_label_span && !failure_span.overlaps(span) {
             Some(failure_span)
         } else {
@@ -518,7 +548,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
                                 GenericArgKind::Type(_) => self
                                     .next_ty_var(TypeVariableOrigin {
-                                        span: rustc_span::DUMMY_SP,
+                                        span: DUMMY_SP,
                                         kind: TypeVariableOriginKind::MiscVariable,
                                     })
                                     .into(),
@@ -526,7 +556,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     .next_const_var(
                                         arg.ty(),
                                         ConstVariableOrigin {
-                                            span: rustc_span::DUMMY_SP,
+                                            span: DUMMY_SP,
                                             kind: ConstVariableOriginKind::MiscVariable,
                                         },
                                     )
@@ -547,7 +577,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
                 let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
-                    span: rustc_span::DUMMY_SP,
+                    span: DUMMY_SP,
                     kind: TypeVariableOriginKind::MiscVariable,
                 }));
                 if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
@@ -584,7 +614,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
                 let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
-                    span: rustc_span::DUMMY_SP,
+                    span: DUMMY_SP,
                     kind: TypeVariableOriginKind::MiscVariable,
                 }));
                 if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
@@ -606,6 +636,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label: None,
+                was_written: path.as_ref().map(|_| ()),
+                path: path.unwrap_or_default(),
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -615,6 +647,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label: None,
+                was_written: path.as_ref().map(|_| ()),
+                path: path.unwrap_or_default(),
             }),
             TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn {
                 span,
@@ -624,6 +658,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 infer_subdiags,
                 multi_suggestions,
                 bad_label: None,
+                was_written: path.as_ref().map(|_| ()),
+                path: path.unwrap_or_default(),
             }),
         }
     }
@@ -688,22 +724,23 @@ impl<'tcx> InferSource<'tcx> {
 }
 
 impl<'tcx> InferSourceKind<'tcx> {
-    fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) {
+    fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Option<PathBuf>) {
+        let mut path = None;
         match *self {
             InferSourceKind::LetBinding { ty, .. }
             | InferSourceKind::ClosureArg { ty, .. }
             | InferSourceKind::ClosureReturn { ty, .. } => {
                 if ty.is_closure() {
-                    ("closure", closure_as_fn_str(infcx, ty))
+                    ("closure", closure_as_fn_str(infcx, ty), path)
                 } else if !ty.is_ty_or_numeric_infer() {
-                    ("normal", ty_to_string(infcx, ty, None))
+                    ("normal", infcx.tcx.short_ty_string(ty, &mut path), path)
                 } else {
-                    ("other", String::new())
+                    ("other", String::new(), path)
                 }
             }
             // FIXME: We should be able to add some additional info here.
             InferSourceKind::GenericArg { .. }
-            | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()),
+            | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new(), path),
         }
     }
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index d04d30b3cb0..91cef02c7d1 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -170,7 +170,9 @@ fn configure_and_expand(
         let mut old_path = OsString::new();
         if cfg!(windows) {
             old_path = env::var_os("PATH").unwrap_or(old_path);
-            let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs();
+            let mut new_path = Vec::from_iter(
+                sess.host_filesearch(PathKind::All).search_paths().map(|p| p.dir.clone()),
+            );
             for path in env::split_paths(&old_path) {
                 if !new_path.contains(&path) {
                     new_path.push(path);
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 16e3b8c11c1..b2403836397 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -105,7 +105,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
         BuiltinLintDiag::RedundantImport(spans, ident) => {
             for (span, is_imported) in spans {
                 let introduced = if is_imported { "imported" } else { "defined" };
-                let span_msg = if span.is_dummy() { "by prelude" } else { "here" };
+                let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" };
                 diag.span_label(
                     span,
                     format!("the item `{ident}` is already {introduced} {span_msg}"),
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 111a4fdcea1..503caa35358 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1074,10 +1074,14 @@ impl UnusedParens {
                 // Otherwise proceed with linting.
                 _ => {}
             }
-            let spans = inner
-                .span
-                .find_ancestor_inside(value.span)
-                .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())));
+            let spans = if !value.span.from_expansion() {
+                inner
+                    .span
+                    .find_ancestor_inside(value.span)
+                    .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
+            } else {
+                None
+            };
             self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false);
         }
     }
@@ -1233,11 +1237,13 @@ impl EarlyLintPass for UnusedParens {
                         if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
                     ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
                     _ => {
-                        let spans = r
-                            .span
-                            .find_ancestor_inside(ty.span)
-                            .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())));
-
+                        let spans = if !ty.span.from_expansion() {
+                            r.span
+                                .find_ancestor_inside(ty.span)
+                                .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
+                        } else {
+                            None
+                        };
                         self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
                     }
                 }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index baa2e1ff602..58760be921a 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -19,12 +19,7 @@ use crate::errors;
 
 use std::path::PathBuf;
 
-pub fn find_native_static_library(
-    name: &str,
-    verbatim: bool,
-    search_paths: &[PathBuf],
-    sess: &Session,
-) -> PathBuf {
+pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
     let formats = if verbatim {
         vec![("".into(), "".into())]
     } else {
@@ -35,9 +30,9 @@ pub fn find_native_static_library(
         if os == unix { vec![os] } else { vec![os, unix] }
     };
 
-    for path in search_paths {
+    for path in sess.target_filesearch(PathKind::Native).search_paths() {
         for (prefix, suffix) in &formats {
-            let test = path.join(format!("{prefix}{name}{suffix}"));
+            let test = path.dir.join(format!("{prefix}{name}{suffix}"));
             if test.exists() {
                 return test;
             }
@@ -60,8 +55,7 @@ fn find_bundled_library(
         && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
     {
         let verbatim = verbatim.unwrap_or(false);
-        let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs();
-        return find_native_static_library(name.as_str(), verbatim, search_paths, sess)
+        return find_native_static_library(name.as_str(), verbatim, sess)
             .file_name()
             .and_then(|s| s.to_str())
             .map(Symbol::intern);
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 7b10ea53524..c057f7e921e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2009,7 +2009,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
 
                 let trait_def = tcx.trait_def(trait_ref.def_id);
-                if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() {
+                if let Ok(mut an) = trait_def.ancestors(tcx, def_id) {
                     if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
                         self.tables.impl_parent.set_some(def_id.index, parent.into());
                     }
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 9e8ee92b5d9..6c3ff237d59 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -10,7 +10,6 @@ derivative = "2.2.0"
 either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
-measureme = "11"
 polonius-engine = "0.13.0"
 rustc-rayon = { version = "0.5.0", optional = true }
 rustc-rayon-core = { version = "0.5.0", optional = true }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 41df2e3b587..15bd5c08965 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -978,12 +978,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"),
 
             AddressOf(mutability, ref place) => {
-                let kind_str = match mutability {
-                    Mutability::Mut => "mut",
-                    Mutability::Not => "const",
-                };
-
-                write!(fmt, "&raw {kind_str} {place:?}")
+                write!(fmt, "&raw {mut_str} {place:?}", mut_str = mutability.ptr_str())
             }
 
             Aggregate(ref kind, ref places) => {
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index c1548eb99f5..faa137019cb 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -555,6 +555,19 @@ impl Key for HirId {
     }
 }
 
+impl Key for (LocalDefId, HirId) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.hir().span(self.1)
+    }
+
+    #[inline(always)]
+    fn key_as_def_id(&self) -> Option<DefId> {
+        Some(self.0.into())
+    }
+}
+
 impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
     type Cache<V> = DefaultCache<Self, V>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5ef7a20f460..394515f091f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -983,6 +983,9 @@ rustc_queries! {
     query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
         desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
     }
+    query lookup_method_for_diagnostic((def_id, hir_id): (LocalDefId, hir::HirId)) -> Option<DefId> {
+        desc { |tcx| "lookup_method_for_diagnostics `{}`", tcx.def_path_str(def_id) }
+    }
 
     query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
         desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key) }
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 6555a687152..4ce6f7747a5 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -8,8 +8,6 @@ use crate::query::{
 };
 use crate::ty::TyCtxt;
 use field_offset::FieldOffset;
-use measureme::StringId;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::AtomicU64;
 use rustc_data_structures::sync::WorkerLocal;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -22,16 +20,6 @@ use rustc_query_system::HandleCycleError;
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 use std::ops::Deref;
 
-pub struct QueryKeyStringCache {
-    pub def_id_cache: FxHashMap<DefId, StringId>,
-}
-
-impl QueryKeyStringCache {
-    pub fn new() -> QueryKeyStringCache {
-        QueryKeyStringCache { def_id_cache: Default::default() }
-    }
-}
-
 pub struct DynamicQuery<'tcx, C: QueryCache> {
     pub name: &'static str,
     pub eval_always: bool,
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 95d1e08b58b..211d403998f 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -6,6 +6,7 @@ use crate::{mir, ty};
 use std::fmt::Write;
 
 use crate::query::Providers;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -415,6 +416,72 @@ impl BorrowKind {
     }
 }
 
+pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>(
+    parent_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>,
+    child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>,
+    mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T,
+) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> {
+    std::iter::from_coroutine(move || {
+        let mut child_captures = child_captures.into_iter().enumerate().peekable();
+
+        // One parent capture may correspond to several child captures if we end up
+        // refining the set of captures via edition-2021 precise captures. We want to
+        // match up any number of child captures with one parent capture, so we keep
+        // peeking off this `Peekable` until the child doesn't match anymore.
+        for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() {
+            // Make sure we use every field at least once, b/c why are we capturing something
+            // if it's not used in the inner coroutine.
+            let mut field_used_at_least_once = false;
+
+            // A parent matches a child if they share the same prefix of projections.
+            // The child may have more, if it is capturing sub-fields out of
+            // something that is captured by-move in the parent closure.
+            while child_captures.peek().map_or(false, |(_, child_capture)| {
+                child_prefix_matches_parent_projections(parent_capture, child_capture)
+            }) {
+                let (child_field_idx, child_capture) = child_captures.next().unwrap();
+                // This analysis only makes sense if the parent capture is a
+                // prefix of the child capture.
+                assert!(
+                    child_capture.place.projections.len() >= parent_capture.place.projections.len(),
+                    "parent capture ({parent_capture:#?}) expected to be prefix of \
+                    child capture ({child_capture:#?})"
+                );
+
+                yield for_each(
+                    (parent_field_idx, parent_capture),
+                    (child_field_idx, child_capture),
+                );
+
+                field_used_at_least_once = true;
+            }
+
+            // Make sure the field was used at least once.
+            assert!(
+                field_used_at_least_once,
+                "we captured {parent_capture:#?} but it was not used in the child coroutine?"
+            );
+        }
+        assert_eq!(child_captures.next(), None, "leftover child captures?");
+    })
+}
+
+fn child_prefix_matches_parent_projections(
+    parent_capture: &ty::CapturedPlace<'_>,
+    child_capture: &ty::CapturedPlace<'_>,
+) -> bool {
+    let HirPlaceBase::Upvar(parent_base) = parent_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+    let HirPlaceBase::Upvar(child_base) = child_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+
+    parent_base.var_path.hir_id == child_base.var_path.hir_id
+        && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections)
+            .all(|(child, parent)| child.kind == parent.kind)
+}
+
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { closure_typeinfo, ..*providers }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ee4dc9744ac..e6b773ae512 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -77,9 +77,10 @@ pub use rustc_type_ir::ConstKind::{
 pub use rustc_type_ir::*;
 
 pub use self::closure::{
-    is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
-    CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
-    RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL,
+    analyze_coroutine_closure_captures, is_ancestor_or_same_capture, place_to_string_for_capture,
+    BorrowKind, CaptureInfo, CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap,
+    MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath,
+    CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{
     Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 20ebd87c3d4..0bd009cd51d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -671,13 +671,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!("(", print(ty), ") is ", write("{pat:?}"))
             }
             ty::RawPtr(ty, mutbl) => {
-                p!(write(
-                    "*{} ",
-                    match mutbl {
-                        hir::Mutability::Mut => "mut",
-                        hir::Mutability::Not => "const",
-                    }
-                ));
+                p!(write("*{} ", mutbl.ptr_str()));
                 p!(print(ty))
             }
             ty::Ref(r, ty, mutbl) => {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index dd73f0f4a35..ad64745d579 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -771,7 +771,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
     }
 }
 
-#[derive(Debug, Copy, Clone, HashStable)]
+#[derive(Debug, Copy, Clone, HashStable, TypeFoldable, TypeVisitable)]
 pub enum UpvarArgs<'tcx> {
     Closure(GenericArgsRef<'tcx>),
     Coroutine(GenericArgsRef<'tcx>),
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index dd3a36c7bf8..2038d3f8448 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -1,8 +1,3 @@
-use rustc_data_structures::sync::Lock;
-
-use std::fmt::Debug;
-use std::time::{Duration, Instant};
-
 #[cfg(test)]
 mod tests;
 
@@ -26,46 +21,6 @@ pub fn to_readable_str(mut val: usize) -> String {
     groups.join("_")
 }
 
-pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T
-where
-    F: FnOnce() -> T,
-{
-    let start = Instant::now();
-    let rv = f();
-    let duration = start.elapsed();
-    let mut accu = accu.lock();
-    *accu += duration;
-    rv
-}
-
-pub fn indent<R, F>(op: F) -> R
-where
-    R: Debug,
-    F: FnOnce() -> R,
-{
-    // Use in conjunction with the log post-processor like `src/etc/indenter`
-    // to make debug output more readable.
-    debug!(">>");
-    let r = op();
-    debug!("<< (Result = {:?})", r);
-    r
-}
-
-pub struct Indenter {
-    _cannot_construct_outside_of_this_module: (),
-}
-
-impl Drop for Indenter {
-    fn drop(&mut self) {
-        debug!("<<");
-    }
-}
-
-pub fn indenter() -> Indenter {
-    debug!(">>");
-    Indenter { _cannot_construct_outside_of_this_module: () }
-}
-
 // const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
 pub const fn c_name(name: &'static str) -> &'static str {
     // FIXME Simplify the implementation once more `str` methods get const-stable.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index a3e6c2abc51..03195a122b4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -674,6 +674,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         if let Some(span) = sp
             && self.tcx.sess.source_map().is_span_accessible(span)
             && interpreted_as_const.is_none()
+            && scrut.is_some()
         {
             let mut bindings = vec![];
             pat.each_binding(|name, _, _, _| bindings.push(name));
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index b26f968bf5e..3d6c1a95204 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -71,7 +71,7 @@
 
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
+use rustc_middle::hir::place::{Projection, ProjectionKind};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
 use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt};
@@ -124,44 +124,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             .tuple_fields()
             .len();
 
-        let mut field_remapping = UnordMap::default();
-
-        let mut child_captures = tcx
-            .closure_captures(coroutine_def_id)
-            .iter()
-            .copied()
-            // By construction we capture all the args first.
-            .skip(num_args)
-            .enumerate()
-            .peekable();
-
-        // One parent capture may correspond to several child captures if we end up
-        // refining the set of captures via edition-2021 precise captures. We want to
-        // match up any number of child captures with one parent capture, so we keep
-        // peeking off this `Peekable` until the child doesn't match anymore.
-        for (parent_field_idx, parent_capture) in
-            tcx.closure_captures(parent_def_id).iter().copied().enumerate()
-        {
-            // Make sure we use every field at least once, b/c why are we capturing something
-            // if it's not used in the inner coroutine.
-            let mut field_used_at_least_once = false;
-
-            // A parent matches a child if they share the same prefix of projections.
-            // The child may have more, if it is capturing sub-fields out of
-            // something that is captured by-move in the parent closure.
-            while child_captures.peek().map_or(false, |(_, child_capture)| {
-                child_prefix_matches_parent_projections(parent_capture, child_capture)
-            }) {
-                let (child_field_idx, child_capture) = child_captures.next().unwrap();
-
-                // This analysis only makes sense if the parent capture is a
-                // prefix of the child capture.
-                assert!(
-                    child_capture.place.projections.len() >= parent_capture.place.projections.len(),
-                    "parent capture ({parent_capture:#?}) expected to be prefix of \
-                    child capture ({child_capture:#?})"
-                );
-
+        let field_remapping: UnordMap<_, _> = ty::analyze_coroutine_closure_captures(
+            tcx.closure_captures(parent_def_id).iter().copied(),
+            tcx.closure_captures(coroutine_def_id).iter().skip(num_args).copied(),
+            |(parent_field_idx, parent_capture), (child_field_idx, child_capture)| {
                 // Store this set of additional projections (fields and derefs).
                 // We need to re-apply them later.
                 let child_precise_captures =
@@ -192,7 +158,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                     ),
                 };
 
-                field_remapping.insert(
+                (
                     FieldIdx::from_usize(child_field_idx + num_args),
                     (
                         FieldIdx::from_usize(parent_field_idx + num_args),
@@ -200,18 +166,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                         needs_deref,
                         child_precise_captures,
                     ),
-                );
-
-                field_used_at_least_once = true;
-            }
-
-            // Make sure the field was used at least once.
-            assert!(
-                field_used_at_least_once,
-                "we captured {parent_capture:#?} but it was not used in the child coroutine?"
-            );
-        }
-        assert_eq!(child_captures.next(), None, "leftover child captures?");
+                )
+            },
+        )
+        .collect();
 
         if coroutine_kind == ty::ClosureKind::FnOnce {
             assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
@@ -241,22 +199,6 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
     }
 }
 
-fn child_prefix_matches_parent_projections(
-    parent_capture: &ty::CapturedPlace<'_>,
-    child_capture: &ty::CapturedPlace<'_>,
-) -> bool {
-    let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
-        bug!("expected capture to be an upvar");
-    };
-    let PlaceBase::Upvar(child_base) = child_capture.place.base else {
-        bug!("expected capture to be an upvar");
-    };
-
-    parent_base.var_path.hir_id == child_base.var_path.hir_id
-        && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections)
-            .all(|(child, parent)| child.kind == parent.kind)
-}
-
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
     field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 353c3f41ed8..1c1ca0bac81 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -697,7 +697,6 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         let expn_data = prefix_span.ctxt().outer_expn_data();
 
         if expn_data.edition >= Edition::Edition2021 {
-            let mut silence = false;
             // In Rust 2021, this is a hard error.
             let sugg = if prefix == "rb" {
                 Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
@@ -705,25 +704,20 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                 if self.cursor.first() == '\''
                     && let Some(start) = self.last_lifetime
                     && self.cursor.third() != '\''
+                    && let end = self.mk_sp(self.pos, self.pos + BytePos(1))
+                    && !self.psess.source_map().is_multiline(start.until(end))
                 {
-                    // An "unclosed `char`" error will be emitted already, silence redundant error.
-                    silence = true;
-                    Some(errors::UnknownPrefixSugg::MeantStr {
-                        start,
-                        end: self.mk_sp(self.pos, self.pos + BytePos(1)),
-                    })
+                    // FIXME: An "unclosed `char`" error will be emitted already in some cases,
+                    // but it's hard to silence this error while not also silencing important cases
+                    // too. We should use the error stashing machinery instead.
+                    Some(errors::UnknownPrefixSugg::MeantStr { start, end })
                 } else {
                     Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
                 }
             } else {
                 None
             };
-            let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg };
-            if silence {
-                self.dcx().create_err(err).delay_as_bug();
-            } else {
-                self.dcx().emit_err(err);
-            }
+            self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
         } else {
             // Before Rust 2021, only emit a lint for migration.
             self.psess.buffer_lint_with_diagnostic(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 012285e4644..00947a4c585 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3585,8 +3585,7 @@ impl<'a> Parser<'a> {
 
             match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
                 Ok(_) => {
-                    if let Some(f) =
-                        parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)).ok()
+                    if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
                     {
                         // Only include the field if there's no parse error for the field name.
                         fields.push(f);
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 52767155532..3373835d813 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -13,6 +13,7 @@
 extern crate rustc_middle;
 
 use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
+use crate::profiling_support::QueryKeyStringCache;
 use field_offset::offset_of;
 use rustc_data_structures::stable_hasher::HashStable;
 use rustc_data_structures::sync::AtomicU64;
@@ -21,9 +22,7 @@ use rustc_middle::dep_graph::DepNodeIndex;
 use rustc_middle::dep_graph::{self, DepKind, DepKindStruct};
 use rustc_middle::query::erase::{erase, restore, Erase};
 use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
-use rustc_middle::query::plumbing::{
-    DynamicQuery, QueryKeyStringCache, QuerySystem, QuerySystemFns,
-};
+use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
 use rustc_middle::query::AsLocalKey;
 use rustc_middle::query::{
     queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index fbc6db93e01..e0d7a4f0451 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,13 +1,23 @@
 use measureme::{StringComponent, StringId};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
-use rustc_middle::query::plumbing::QueryKeyStringCache;
 use rustc_middle::ty::TyCtxt;
 use rustc_query_system::query::QueryCache;
 use std::fmt::Debug;
 use std::io::Write;
 
+pub(crate) struct QueryKeyStringCache {
+    def_id_cache: FxHashMap<DefId, StringId>,
+}
+
+impl QueryKeyStringCache {
+    fn new() -> QueryKeyStringCache {
+        QueryKeyStringCache { def_id_cache: Default::default() }
+    }
+}
+
 struct QueryKeyStringBuilder<'p, 'tcx> {
     profiler: &'p SelfProfiler,
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 2bc7cb99547..6042aa6a2d2 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -541,12 +541,7 @@ impl<D: Deps> EncoderState<D> {
         record_graph: &Option<Lock<DepGraphQuery>>,
     ) -> DepNodeIndex {
         node.encode::<D>(&mut self.encoder);
-        self.record(
-            node.node,
-            node.edges.len(),
-            |_| node.edges[..].iter().copied().collect(),
-            record_graph,
-        )
+        self.record(node.node, node.edges.len(), |_| node.edges[..].to_vec(), record_graph)
     }
 
     /// Encodes a node that was promoted from the previous graph. It reads the information directly from
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 76fe36a77cb..3d9380a3ebd 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1391,6 +1391,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
             redundant_spans.sort();
             redundant_spans.dedup();
+            /* FIXME(unused_imports): Add this back as a new lint
             self.lint_buffer.buffer_lint_with_diagnostic(
                 UNUSED_IMPORTS,
                 id,
@@ -1398,6 +1399,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 format!("the item `{source}` is imported redundantly"),
                 BuiltinLintDiag::RedundantImport(redundant_spans, source),
             );
+            */
             return true;
         }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 39ccf6d3714..b8221d9d7f9 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -177,7 +177,7 @@ enum ImplTraitContext {
 
 /// Used for tracking import use types which will be used for redundant import checking.
 /// ### Used::Scope Example
-///  ```rust,compile_fail
+///  ```rust,ignore (redundant_imports)
 /// #![deny(unused_imports)]
 /// use std::mem::drop;
 /// fn main() {
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 0ebcad3cdb8..0bc7579918c 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -194,12 +194,12 @@ pub fn attrs_to_doc_fragments<'a>(
     for (attr, item_id) in attrs {
         if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
             let doc = beautify_doc_string(doc_str, comment_kind);
-            let kind = if attr.is_doc_comment() {
-                DocFragmentKind::SugaredDoc
+            let (span, kind) = if attr.is_doc_comment() {
+                (attr.span, DocFragmentKind::SugaredDoc)
             } else {
-                DocFragmentKind::RawDoc
+                (span_for_value(attr), DocFragmentKind::RawDoc)
             };
-            let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 };
+            let fragment = DocFragment { span, doc, kind, item_id, indent: 0 };
             doc_fragments.push(fragment);
         } else if !doc_only {
             other_attrs.push(attr.clone());
@@ -211,6 +211,16 @@ pub fn attrs_to_doc_fragments<'a>(
     (doc_fragments, other_attrs)
 }
 
+fn span_for_value(attr: &ast::Attribute) -> Span {
+    if let ast::AttrKind::Normal(normal) = &attr.kind
+        && let ast::AttrArgs::Eq(_, ast::AttrArgsEq::Hir(meta)) = &normal.item.args
+    {
+        meta.span.with_ctxt(attr.span.ctxt())
+    } else {
+        attr.span
+    }
+}
+
 /// Return the doc-comments on this item, grouped by the module they came from.
 /// The module can be different if this is a re-export with added documentation.
 ///
@@ -482,15 +492,36 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
 
 /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
 ///
-/// This method will return `None` if we cannot construct a span from the source map or if the
-/// fragments are not all sugared doc comments. It's difficult to calculate the correct span in
-/// that case due to escaping and other source features.
+/// This method does not always work, because markdown bytes don't necessarily match source bytes,
+/// like if escapes are used in the string. In this case, it returns `None`.
+///
+/// This method will return `Some` only if:
+///
+/// - The doc is made entirely from sugared doc comments, which cannot contain escapes
+/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal
+/// - The doc comes from `include_str!`
 pub fn source_span_for_markdown_range(
     tcx: TyCtxt<'_>,
     markdown: &str,
     md_range: &Range<usize>,
     fragments: &[DocFragment],
 ) -> Option<Span> {
+    if let &[fragment] = &fragments
+        && fragment.kind == DocFragmentKind::RawDoc
+        && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span)
+        && snippet.trim_end() == markdown.trim_end()
+        && let Ok(md_range_lo) = u32::try_from(md_range.start)
+        && let Ok(md_range_hi) = u32::try_from(md_range.end)
+    {
+        // Single fragment with string that contains same bytes as doc.
+        return Some(Span::new(
+            fragment.span.lo() + rustc_span::BytePos(md_range_lo),
+            fragment.span.lo() + rustc_span::BytePos(md_range_hi),
+            fragment.span.ctxt(),
+            fragment.span.parent(),
+        ));
+    }
+
     let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
 
     if !is_all_sugared_doc {
diff --git a/compiler/rustc_serialize/src/int_overflow.rs b/compiler/rustc_serialize/src/int_overflow.rs
new file mode 100644
index 00000000000..f2aac2ef711
--- /dev/null
+++ b/compiler/rustc_serialize/src/int_overflow.rs
@@ -0,0 +1,65 @@
+// This would belong to `rustc_data_structures`, but `rustc_serialize` needs it too.
+
+/// Addition, but only overflow checked when `cfg(debug_assertions)` is set
+/// instead of respecting `-Coverflow-checks`.
+///
+/// This exists for performance reasons, as we ship rustc with overflow checks.
+/// While overflow checks are perf neutral in almost all of the compiler, there
+/// are a few particularly hot areas where we don't want overflow checks in our
+/// dist builds. Overflow is still a bug there, so we want overflow check for
+/// builds with debug assertions.
+///
+/// That's a long way to say that this should be used in areas where overflow
+/// is a bug but overflow checking is too slow.
+pub trait DebugStrictAdd {
+    /// See [`DebugStrictAdd`].
+    fn debug_strict_add(self, other: Self) -> Self;
+}
+
+macro_rules! impl_debug_strict_add {
+    ($( $ty:ty )*) => {
+        $(
+            impl DebugStrictAdd for $ty {
+                fn debug_strict_add(self, other: Self) -> Self {
+                    if cfg!(debug_assertions) {
+                        self + other
+                    } else {
+                        self.wrapping_add(other)
+                    }
+                }
+            }
+        )*
+    };
+}
+
+/// See [`DebugStrictAdd`].
+pub trait DebugStrictSub {
+    /// See [`DebugStrictAdd`].
+    fn debug_strict_sub(self, other: Self) -> Self;
+}
+
+macro_rules! impl_debug_strict_sub {
+    ($( $ty:ty )*) => {
+        $(
+            impl DebugStrictSub for $ty {
+                fn debug_strict_sub(self, other: Self) -> Self {
+                    if cfg!(debug_assertions) {
+                        self - other
+                    } else {
+                        self.wrapping_sub(other)
+                    }
+                }
+            }
+        )*
+    };
+}
+
+impl_debug_strict_add! {
+    u8 u16 u32 u64 u128 usize
+    i8 i16 i32 i64 i128 isize
+}
+
+impl_debug_strict_sub! {
+    u8 u16 u32 u64 u128 usize
+    i8 i16 i32 i64 i128 isize
+}
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index ca661bac78c..44324804468 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -1,6 +1,10 @@
 use crate::opaque::MemDecoder;
 use crate::serialize::Decoder;
 
+// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
+// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
+use crate::int_overflow::DebugStrictAdd;
+
 /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
 pub const fn max_leb128_len<T>() -> usize {
     // The longest LEB128 encoding for an integer uses 7 bits per byte.
@@ -24,7 +28,7 @@ macro_rules! impl_write_unsigned_leb128 {
                         *out.get_unchecked_mut(i) = value as u8;
                     }
 
-                    i += 1;
+                    i = i.debug_strict_add(1);
                     break;
                 } else {
                     unsafe {
@@ -32,7 +36,7 @@ macro_rules! impl_write_unsigned_leb128 {
                     }
 
                     value >>= 7;
-                    i += 1;
+                    i = i.debug_strict_add(1);
                 }
             }
 
@@ -69,7 +73,7 @@ macro_rules! impl_read_unsigned_leb128 {
                 } else {
                     result |= ((byte & 0x7F) as $int_ty) << shift;
                 }
-                shift += 7;
+                shift = shift.debug_strict_add(7);
             }
         }
     };
@@ -101,7 +105,7 @@ macro_rules! impl_write_signed_leb128 {
                     *out.get_unchecked_mut(i) = byte;
                 }
 
-                i += 1;
+                i = i.debug_strict_add(1);
 
                 if !more {
                     break;
@@ -130,7 +134,7 @@ macro_rules! impl_read_signed_leb128 {
             loop {
                 byte = decoder.read_u8();
                 result |= <$int_ty>::from(byte & 0x7F) << shift;
-                shift += 7;
+                shift = shift.debug_strict_add(7);
 
                 if (byte & 0x80) == 0 {
                     break;
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index b67b7d79d97..5a9403e0a85 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -23,5 +23,6 @@ pub use self::serialize::{Decodable, Decoder, Encodable, Encoder};
 
 mod serialize;
 
+pub mod int_overflow;
 pub mod leb128;
 pub mod opaque;
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index cc8d1c25092..eec83c02d35 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -7,6 +7,10 @@ use std::ops::Range;
 use std::path::Path;
 use std::path::PathBuf;
 
+// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
+// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
+use crate::int_overflow::DebugStrictAdd;
+
 // -----------------------------------------------------------------------------
 // Encoder
 // -----------------------------------------------------------------------------
@@ -65,7 +69,7 @@ impl FileEncoder {
         // Tracking position this way instead of having a `self.position` field
         // means that we only need to update `self.buffered` on a write call,
         // as opposed to updating `self.position` and `self.buffered`.
-        self.flushed + self.buffered
+        self.flushed.debug_strict_add(self.buffered)
     }
 
     #[cold]
@@ -119,7 +123,7 @@ impl FileEncoder {
         }
         if let Some(dest) = self.buffer_empty().get_mut(..buf.len()) {
             dest.copy_from_slice(buf);
-            self.buffered += buf.len();
+            self.buffered = self.buffered.debug_strict_add(buf.len());
         } else {
             self.write_all_cold_path(buf);
         }
@@ -158,7 +162,7 @@ impl FileEncoder {
         if written > N {
             Self::panic_invalid_write::<N>(written);
         }
-        self.buffered += written;
+        self.buffered = self.buffered.debug_strict_add(written);
     }
 
     #[cold]
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index a4919b25fe3..34acb4ea10f 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -18,7 +18,7 @@ use rustc_feature::UnstableFeatures;
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm};
-use rustc_target::spec::LinkSelfContainedComponents;
+use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures};
 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
 use std::collections::btree_map::{
     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
@@ -292,6 +292,48 @@ impl LinkSelfContained {
     }
 }
 
+/// The different values that `-Z linker-features` can take on the CLI: a list of individually
+/// enabled or disabled features used during linking.
+///
+/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
+/// used to turn `LinkerFeatures` on or off, without needing to change the linker flavor:
+/// - using the system lld, or the self-contained `rust-lld` linker
+/// - using a C/C++ compiler to drive the linker (not yet exposed on the CLI)
+/// - etc.
+#[derive(Default, Copy, Clone, PartialEq, Debug)]
+pub struct LinkerFeaturesCli {
+    /// The linker features that are enabled on the CLI, using the `+feature` syntax.
+    pub enabled: LinkerFeatures,
+
+    /// The linker features that are disabled on the CLI, using the `-feature` syntax.
+    pub disabled: LinkerFeatures,
+}
+
+impl LinkerFeaturesCli {
+    /// Accumulates an enabled or disabled feature as specified on the CLI, if possible.
+    /// For example: `+lld`, and `-lld`.
+    pub(crate) fn handle_cli_feature(&mut self, feature: &str) -> Option<()> {
+        // Duplicate flags are reduced as we go, the last occurrence wins:
+        // `+feature,-feature,+feature` only enables the feature, and does not record it as both
+        // enabled and disabled on the CLI.
+        // We also only expose `+/-lld` at the moment, as it's currenty the only implemented linker
+        // feature and toggling `LinkerFeatures::CC` would be a noop.
+        match feature {
+            "+lld" => {
+                self.enabled.insert(LinkerFeatures::LLD);
+                self.disabled.remove(LinkerFeatures::LLD);
+                Some(())
+            }
+            "-lld" => {
+                self.disabled.insert(LinkerFeatures::LLD);
+                self.enabled.remove(LinkerFeatures::LLD);
+                Some(())
+            }
+            _ => None,
+        }
+    }
+}
+
 /// Used with `-Z assert-incr-state`.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum IncrementalStateAssertion {
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 4f0e3354680..aecf5954c4c 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -45,11 +45,6 @@ impl<'a> FileSearch<'a> {
         debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
         FileSearch { sysroot, triple, search_paths, tlib_path, kind }
     }
-
-    /// Returns just the directories within the search paths.
-    pub fn search_path_dirs(&self) -> Vec<PathBuf> {
-        self.search_paths().map(|sp| sp.dir.to_path_buf()).collect()
-    }
 }
 
 pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 5e7c2465097..963c9558c17 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -426,6 +426,8 @@ mod desc {
         "one of supported split dwarf modes (`split` or `single`)";
     pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \
         components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
+    pub const parse_linker_features: &str =
+        "a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld`";
     pub const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
     pub const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
@@ -1269,6 +1271,22 @@ mod parse {
         true
     }
 
+    /// Parse a comma-separated list of enabled and disabled linker features.
+    pub(crate) fn parse_linker_features(slot: &mut LinkerFeaturesCli, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                for feature in s.split(',') {
+                    if slot.handle_cli_feature(feature).is_none() {
+                        return false;
+                    }
+                }
+
+                true
+            }
+            None => false,
+        }
+    }
+
     pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
         match v {
             Some("command") => *slot = Some(WasiExecModel::Command),
@@ -1721,6 +1739,8 @@ options! {
         "link native libraries in the linker invocation (default: yes)"),
     link_only: bool = (false, parse_bool, [TRACKED],
         "link the `.rlink` file generated by `-Z no-link` (default: no)"),
+    linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
+        "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
     lint_mir: bool = (false, parse_bool, [UNTRACKED],
         "lint MIR before and after each transformation"),
     llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED],
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 7ce879807ca..c1e1175b4bd 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -743,6 +743,45 @@ impl Span {
         Some(self)
     }
 
+    /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
+    /// [`SyntaxContext`] the initial span.
+    ///
+    /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
+    /// span that is still local and shares the same [`SyntaxContext`]. For example, given
+    ///
+    /// ```ignore (illustrative example, contains type error)
+    ///  macro_rules! outer {
+    ///      ($x: expr) => {
+    ///          inner!($x)
+    ///      }
+    ///  }
+    ///
+    ///  macro_rules! inner {
+    ///      ($x: expr) => {
+    ///          format!("error: {}", $x)
+    ///          //~^ ERROR mismatched types
+    ///      }
+    ///  }
+    ///
+    ///  fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
+    ///      Err(outer!(x))
+    ///  }
+    /// ```
+    ///
+    /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
+    /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
+    /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
+    /// initial span.
+    pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
+        let mut cur = self;
+        while cur.eq_ctxt(self)
+            && let Some(parent_callsite) = cur.parent_callsite()
+        {
+            cur = parent_callsite;
+        }
+        cur
+    }
+
     /// Edition of the crate from which this span came.
     pub fn edition(self) -> edition::Edition {
         self.ctxt().edition()
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index f721a04d6b9..93d5f06a167 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -218,7 +218,7 @@ impl SourceMap {
     ///
     /// Unlike `load_file`, guarantees that no normalization like BOM-removal
     /// takes place.
-    pub fn load_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> {
+    pub fn load_binary_file(&self, path: &Path) -> io::Result<(Lrc<[u8]>, Span)> {
         let bytes = self.file_loader.read_binary_file(path)?;
 
         // We need to add file to the `SourceMap`, so that it is present
@@ -227,8 +227,16 @@ impl SourceMap {
         // via `mod`, so we try to use real file contents and not just an
         // empty string.
         let text = std::str::from_utf8(&bytes).unwrap_or("").to_string();
-        self.new_source_file(path.to_owned().into(), text);
-        Ok(bytes)
+        let file = self.new_source_file(path.to_owned().into(), text);
+        Ok((
+            bytes,
+            Span::new(
+                file.start_pos,
+                BytePos(file.start_pos.0 + file.source_len.0),
+                SyntaxContext::root(),
+                None,
+            ),
+        ))
     }
 
     // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index e162695a13b..788a52faf56 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -5,6 +5,10 @@ use crate::{BytePos, SpanData};
 
 use rustc_data_structures::fx::FxIndexSet;
 
+// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
+// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
+use rustc_serialize::int_overflow::DebugStrictAdd;
+
 /// A compressed span.
 ///
 /// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only
@@ -166,7 +170,7 @@ impl Span {
                 debug_assert!(len <= MAX_LEN);
                 SpanData {
                     lo: BytePos(self.lo_or_index),
-                    hi: BytePos(self.lo_or_index + len),
+                    hi: BytePos(self.lo_or_index.debug_strict_add(len)),
                     ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),
                     parent: None,
                 }
@@ -179,7 +183,7 @@ impl Span {
                 };
                 SpanData {
                     lo: BytePos(self.lo_or_index),
-                    hi: BytePos(self.lo_or_index + len),
+                    hi: BytePos(self.lo_or_index.debug_strict_add(len)),
                     ctxt: SyntaxContext::root(),
                     parent: Some(parent),
                 }
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 70528c1222c..5ae9a2e2058 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -87,6 +87,20 @@ fn reserved_x18(
     }
 }
 
+fn restricted_for_arm64ec(
+    arch: InlineAsmArch,
+    _reloc_model: RelocModel,
+    _target_features: &FxIndexSet<Symbol>,
+    _target: &Target,
+    _is_clobber: bool,
+) -> Result<(), &'static str> {
+    if arch == InlineAsmArch::Arm64EC {
+        Err("x13, x14, x23, x24, x28, v16-v31 cannot be used for Arm64EC")
+    } else {
+        Ok(())
+    }
+}
+
 def_regs! {
     AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
         x0: reg = ["x0", "w0"],
@@ -102,8 +116,8 @@ def_regs! {
         x10: reg = ["x10", "w10"],
         x11: reg = ["x11", "w11"],
         x12: reg = ["x12", "w12"],
-        x13: reg = ["x13", "w13"],
-        x14: reg = ["x14", "w14"],
+        x13: reg = ["x13", "w13"] % restricted_for_arm64ec,
+        x14: reg = ["x14", "w14"] % restricted_for_arm64ec,
         x15: reg = ["x15", "w15"],
         x16: reg = ["x16", "w16"],
         x17: reg = ["x17", "w17"],
@@ -111,12 +125,12 @@ def_regs! {
         x20: reg = ["x20", "w20"],
         x21: reg = ["x21", "w21"],
         x22: reg = ["x22", "w22"],
-        x23: reg = ["x23", "w23"],
-        x24: reg = ["x24", "w24"],
+        x23: reg = ["x23", "w23"] % restricted_for_arm64ec,
+        x24: reg = ["x24", "w24"] % restricted_for_arm64ec,
         x25: reg = ["x25", "w25"],
         x26: reg = ["x26", "w26"],
         x27: reg = ["x27", "w27"],
-        x28: reg = ["x28", "w28"],
+        x28: reg = ["x28", "w28"] % restricted_for_arm64ec,
         x30: reg = ["x30", "w30", "lr", "wlr"],
         v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"],
         v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"],
@@ -134,22 +148,22 @@ def_regs! {
         v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"],
         v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"],
         v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"],
-        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"],
-        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"],
-        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"],
-        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"],
-        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"],
-        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"],
-        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"],
-        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"],
-        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"],
-        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"],
-        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"],
-        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"],
-        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"],
-        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"],
-        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"],
-        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"],
+        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"] % restricted_for_arm64ec,
+        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"] % restricted_for_arm64ec,
+        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"] % restricted_for_arm64ec,
+        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"] % restricted_for_arm64ec,
+        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"] % restricted_for_arm64ec,
+        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"] % restricted_for_arm64ec,
+        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"] % restricted_for_arm64ec,
+        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"] % restricted_for_arm64ec,
+        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"] % restricted_for_arm64ec,
+        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"] % restricted_for_arm64ec,
+        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"] % restricted_for_arm64ec,
+        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"] % restricted_for_arm64ec,
+        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"] % restricted_for_arm64ec,
+        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec,
+        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec,
+        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec,
         p0: preg = ["p0"],
         p1: preg = ["p1"],
         p2: preg = ["p2"],
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 2e04dca98c5..49de92b86cb 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -9,11 +9,11 @@ use std::str::FromStr;
 pub struct ModifierInfo {
     pub modifier: char,
     pub result: &'static str,
-    pub size: u64,
+    pub size: u16,
 }
 
-impl From<(char, &'static str, u64)> for ModifierInfo {
-    fn from((modifier, result, size): (char, &'static str, u64)) -> Self {
+impl From<(char, &'static str, u16)> for ModifierInfo {
+    fn from((modifier, result, size): (char, &'static str, u16)) -> Self {
         Self { modifier, result, size }
     }
 }
@@ -217,6 +217,7 @@ pub enum InlineAsmArch {
     X86_64,
     Arm,
     AArch64,
+    Arm64EC,
     RiscV32,
     RiscV64,
     Nvptx64,
@@ -246,6 +247,7 @@ impl FromStr for InlineAsmArch {
             "x86_64" => Ok(Self::X86_64),
             "arm" => Ok(Self::Arm),
             "aarch64" => Ok(Self::AArch64),
+            "arm64ec" => Ok(Self::Arm64EC),
             "riscv32" => Ok(Self::RiscV32),
             "riscv64" => Ok(Self::RiscV64),
             "nvptx64" => Ok(Self::Nvptx64),
@@ -341,7 +343,9 @@ impl InlineAsmReg {
         Ok(match arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
-            InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
+            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
+                Self::AArch64(AArch64InlineAsmReg::parse(name)?)
+            }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                 Self::RiscV(RiscVInlineAsmReg::parse(name)?)
             }
@@ -610,7 +614,9 @@ impl InlineAsmRegClass {
                 Self::X86(X86InlineAsmRegClass::parse(name)?)
             }
             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
-            InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
+            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
+                Self::AArch64(AArch64InlineAsmRegClass::parse(name)?)
+            }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                 Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
             }
@@ -783,7 +789,7 @@ pub fn allocatable_registers(
             arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
             map
         }
-        InlineAsmArch::AArch64 => {
+        InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
             let mut map = aarch64::regclass_map();
             aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
             map
@@ -909,6 +915,10 @@ impl InlineAsmClobberAbi {
                 }),
                 _ => Err(&["C", "system", "efiapi"]),
             },
+            InlineAsmArch::Arm64EC => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::AArch64NoX18),
+                _ => Err(&["C", "system"]),
+            },
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
                 _ => Err(&["C", "system", "efiapi"]),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index e94c7f3cc58..3a69b19ee60 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -448,6 +448,28 @@ impl LinkerFlavor {
             | LinkerFlavor::Ptx => false,
         }
     }
+
+    /// For flavors with an `Lld` component, ensure it's enabled. Otherwise, returns the given
+    /// flavor unmodified.
+    pub fn with_lld_enabled(self) -> LinkerFlavor {
+        match self {
+            LinkerFlavor::Gnu(cc, Lld::No) => LinkerFlavor::Gnu(cc, Lld::Yes),
+            LinkerFlavor::Darwin(cc, Lld::No) => LinkerFlavor::Darwin(cc, Lld::Yes),
+            LinkerFlavor::Msvc(Lld::No) => LinkerFlavor::Msvc(Lld::Yes),
+            _ => self,
+        }
+    }
+
+    /// For flavors with an `Lld` component, ensure it's disabled. Otherwise, returns the given
+    /// flavor unmodified.
+    pub fn with_lld_disabled(self) -> LinkerFlavor {
+        match self {
+            LinkerFlavor::Gnu(cc, Lld::Yes) => LinkerFlavor::Gnu(cc, Lld::No),
+            LinkerFlavor::Darwin(cc, Lld::Yes) => LinkerFlavor::Darwin(cc, Lld::No),
+            LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavor::Msvc(Lld::No),
+            _ => self,
+        }
+    }
 }
 
 macro_rules! linker_flavor_cli_impls {
@@ -698,6 +720,58 @@ impl ToJson for LinkSelfContainedComponents {
     }
 }
 
+bitflags::bitflags! {
+    /// The `-Z linker-features` components that can individually be enabled or disabled.
+    ///
+    /// They are feature flags intended to be a more flexible mechanism than linker flavors, and
+    /// also to prevent a combinatorial explosion of flavors whenever a new linker feature is
+    /// required. These flags are "generic", in the sense that they can work on multiple targets on
+    /// the CLI. Otherwise, one would have to select different linkers flavors for each target.
+    ///
+    /// Here are some examples of the advantages they offer:
+    /// - default feature sets for principal flavors, or for specific targets.
+    /// - flavor-specific features: for example, clang offers automatic cross-linking with
+    ///   `--target`, which gcc-style compilers don't support. The *flavor* is still a C/C++
+    ///   compiler, and we don't need to multiply the number of flavors for this use-case. Instead,
+    ///   we can have a single `+target` feature.
+    /// - umbrella features: for example if clang accumulates more features in the future than just
+    ///   the `+target` above. That could be modeled as `+clang`.
+    /// - niche features for resolving specific issues: for example, on Apple targets the linker
+    ///   flag implementing the `as-needed` native link modifier (#99424) is only possible on
+    ///   sufficiently recent linker versions.
+    /// - still allows for discovery and automation, for example via feature detection. This can be
+    ///   useful in exotic environments/build systems.
+    #[derive(Clone, Copy, PartialEq, Eq, Default)]
+    pub struct LinkerFeatures: u8 {
+        /// Invoke the linker via a C/C++ compiler (e.g. on most unix targets).
+        const CC  = 1 << 0;
+        /// Use the lld linker, either the system lld or the self-contained linker `rust-lld`.
+        const LLD = 1 << 1;
+    }
+}
+rustc_data_structures::external_bitflags_debug! { LinkerFeatures }
+
+impl LinkerFeatures {
+    /// Parses a single `-Z linker-features` well-known feature, not a set of flags.
+    pub fn from_str(s: &str) -> Option<LinkerFeatures> {
+        Some(match s {
+            "cc" => LinkerFeatures::CC,
+            "lld" => LinkerFeatures::LLD,
+            _ => return None,
+        })
+    }
+
+    /// Returns whether the `lld` linker feature is enabled.
+    pub fn is_lld_enabled(self) -> bool {
+        self.contains(LinkerFeatures::LLD)
+    }
+
+    /// Returns whether the `cc` linker feature is enabled.
+    pub fn is_cc_enabled(self) -> bool {
+        self.contains(LinkerFeatures::CC)
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
 pub enum PanicStrategy {
     Unwind,
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
index becd2fd7afb..970b43ad109 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs
@@ -18,8 +18,6 @@ pub fn target() -> Target {
             "/SAFESEH",
         ],
     );
-    // Workaround for #95429
-    base.has_thread_local = false;
 
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
index b68316f2830..ae1a44e44a8 100644
--- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
@@ -18,8 +18,6 @@ pub fn target() -> Target {
             "/SAFESEH",
         ],
     );
-    // Workaround for #95429
-    base.has_thread_local = false;
 
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 8813955f2af..397e104512f 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -181,9 +181,9 @@ pub enum TyKind<I: Interner> {
     /// Looking at the following example, the witness for this coroutine
     /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
     ///
-    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
+    /// ```
     /// #![feature(coroutines)]
-    /// |a| {
+    /// static |a| {
     ///     let x = &vec![3];
     ///     yield a;
     ///     yield x[0];
@@ -373,17 +373,8 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
             Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
             Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
             Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
-            RawPtr(ty, mutbl) => {
-                match mutbl {
-                    Mutability::Mut => write!(f, "*mut "),
-                    Mutability::Not => write!(f, "*const "),
-                }?;
-                write!(f, "{:?}", &this.wrap(ty))
-            }
-            Ref(r, t, m) => match m {
-                Mutability::Mut => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)),
-                Mutability::Not => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)),
-            },
+            RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)),
+            Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)),
             FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(),
             FnPtr(s) => write!(f, "{:?}", &this.wrap(s)),
             Dynamic(p, r, repr) => match repr {
diff --git a/config.example.toml b/config.example.toml
index b8cdc2ec848..0d4b4e9e7e0 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -50,7 +50,7 @@
 #
 # Note that many of the LLVM options are not currently supported for
 # downloading. Currently only the "assertions" option can be toggled.
-#download-ci-llvm = if rust.channel == "dev" { "if-unchanged" } else { false }
+#download-ci-llvm = if rust.channel == "dev" || rust.download-rustc != false { "if-unchanged" } else { false }
 
 # Indicates whether the LLVM build is a Release or Debug build
 #optimize = true
@@ -302,7 +302,7 @@
 
 # Set the bootstrap/download cache path. It is useful when building rust
 # repeatedly in a CI invironment.
-# bootstrap-cache-path = /shared/cache
+#bootstrap-cache-path = /path/to/shared/cache
 
 # Enable a build of the extended Rust tool set which is not only the compiler
 # but also tools such as Cargo. This will also produce "combined installers"
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index f638c5cf8c7..dec04d7e421 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -151,7 +151,6 @@
 #![feature(slice_from_ptr_range)]
 #![feature(slice_index_methods)]
 #![feature(slice_ptr_get)]
-#![feature(slice_ptr_len)]
 #![feature(slice_range)]
 #![feature(std_internals)]
 #![feature(str_internals)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 0883080d735..1134c7f833e 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -259,6 +259,17 @@ impl<T, A: Allocator> RawVec<T, A> {
         Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc }
     }
 
+    /// A convenience method for hoisting the non-null precondition out of [`RawVec::from_raw_parts_in`].
+    ///
+    /// # Safety
+    ///
+    /// See [`RawVec::from_raw_parts_in`].
+    #[inline]
+    pub(crate) unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self {
+        let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } };
+        Self { ptr: Unique::from(ptr), cap, alloc }
+    }
+
     /// Gets a raw pointer to the start of the allocation. Note that this is
     /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 569db54b137..a320a244abd 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -884,7 +884,10 @@ impl<T, A: Allocator> Rc<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
-    pub fn pin_in(value: T, alloc: A) -> Pin<Self> {
+    pub fn pin_in(value: T, alloc: A) -> Pin<Self>
+    where
+        A: 'static,
+    {
         unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) }
     }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 6ae52cc7827..297a273d274 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -807,7 +807,10 @@ impl<T, A: Allocator> Arc<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
-    pub fn pin_in(data: T, alloc: A) -> Pin<Arc<T, A>> {
+    pub fn pin_in(data: T, alloc: A) -> Pin<Arc<T, A>>
+    where
+        A: 'static,
+    {
         unsafe { Pin::new_unchecked(Arc::new_in(data, alloc)) }
     }
 
@@ -815,7 +818,10 @@ impl<T, A: Allocator> Arc<T, A> {
     /// fails.
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn try_pin_in(data: T, alloc: A) -> Result<Pin<Arc<T, A>>, AllocError> {
+    pub fn try_pin_in(data: T, alloc: A) -> Result<Pin<Arc<T, A>>, AllocError>
+    where
+        A: 'static,
+    {
         unsafe { Ok(Pin::new_unchecked(Arc::try_new_in(data, alloc)?)) }
     }
 
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 4907a45e881..88aa1b1b0e0 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -161,7 +161,7 @@ use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, SizedTypeProperties};
 use core::num::NonZero;
-use core::ptr::{self, NonNull};
+use core::ptr;
 
 use super::{InPlaceDrop, InPlaceDstDataSrcBufDrop, SpecFromIter, SpecFromIterNested, Vec};
 
@@ -254,28 +254,30 @@ where
     let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
         let inner = iterator.as_inner().as_into_iter();
         (
-            inner.buf.as_ptr(),
+            inner.buf,
             inner.ptr,
             inner.cap,
-            inner.buf.as_ptr() as *mut T,
+            inner.buf.cast::<T>(),
             inner.end as *const T,
             inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
         )
     };
 
     // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer.
-    let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) };
+    let len = unsafe {
+        SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf.as_ptr() as *mut T, dst_end)
+    };
 
     let src = unsafe { iterator.as_inner().as_into_iter() };
     // check if SourceIter contract was upheld
     // caveat: if they weren't we might not even make it to this point
-    debug_assert_eq!(src_buf, src.buf.as_ptr());
+    debug_assert_eq!(src_buf, src.buf);
     // check InPlaceIterable contract. This is only possible if the iterator advanced the
     // source pointer at all. If it uses unchecked access via TrustedRandomAccess
     // then the source pointer will stay in its initial position and we can't use it as reference
     if src.ptr != src_ptr {
         debug_assert!(
-            unsafe { dst_buf.add(len) as *const _ } <= src.ptr.as_ptr(),
+            unsafe { dst_buf.add(len).cast() } <= src.ptr,
             "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
         );
     }
@@ -315,10 +317,9 @@ where
             let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap);
             let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align);
 
-            let result =
-                alloc.shrink(NonNull::new_unchecked(dst_buf as *mut u8), old_layout, new_layout);
+            let result = alloc.shrink(dst_buf.cast(), old_layout, new_layout);
             let Ok(reallocated) = result else { handle_alloc_error(new_layout) };
-            dst_buf = reallocated.as_ptr() as *mut T;
+            dst_buf = reallocated.cast::<T>();
         }
     } else {
         debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>());
@@ -326,7 +327,7 @@ where
 
     mem::forget(dst_guard);
 
-    let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) };
+    let vec = unsafe { Vec::from_nonnull(dst_buf, len, dst_cap) };
 
     vec
 }
diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs
index 40a540b57fc..4050c250130 100644
--- a/library/alloc/src/vec/in_place_drop.rs
+++ b/library/alloc/src/vec/in_place_drop.rs
@@ -1,4 +1,5 @@
 use core::marker::PhantomData;
+use core::ptr::NonNull;
 use core::ptr::{self, drop_in_place};
 use core::slice::{self};
 
@@ -31,7 +32,7 @@ impl<T> Drop for InPlaceDrop<T> {
 // the source allocation - i.e. before the reallocation happened - to avoid leaking them
 // if some other destructor panics.
 pub(super) struct InPlaceDstDataSrcBufDrop<Src, Dest> {
-    pub(super) ptr: *mut Dest,
+    pub(super) ptr: NonNull<Dest>,
     pub(super) len: usize,
     pub(super) src_cap: usize,
     pub(super) src: PhantomData<Src>,
@@ -42,8 +43,8 @@ impl<Src, Dest> Drop for InPlaceDstDataSrcBufDrop<Src, Dest> {
     fn drop(&mut self) {
         unsafe {
             let _drop_allocation =
-                RawVec::<Src>::from_raw_parts_in(self.ptr.cast::<Src>(), self.src_cap, Global);
-            drop_in_place(core::ptr::slice_from_raw_parts_mut::<Dest>(self.ptr, self.len));
+                RawVec::<Src>::from_nonnull_in(self.ptr.cast::<Src>(), self.src_cap, Global);
+            drop_in_place(core::ptr::slice_from_raw_parts_mut::<Dest>(self.ptr.as_ptr(), self.len));
         };
     }
 }
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index dfd42ca0619..b0226c84833 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -433,7 +433,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
                     // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
                     let alloc = ManuallyDrop::take(&mut self.0.alloc);
                     // RawVec handles deallocation
-                    let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
+                    let _ = RawVec::from_nonnull_in(self.0.buf, self.0.cap, alloc);
                 }
             }
         }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 7e3463bc082..465da39f184 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -603,6 +603,17 @@ impl<T> Vec<T> {
     pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
         unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
     }
+
+    /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts`].
+    ///
+    /// # Safety
+    ///
+    /// See [`Vec::from_raw_parts`].
+    #[inline]
+    #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling
+    pub(crate) unsafe fn from_nonnull(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
+        unsafe { Self::from_nonnull_in(ptr, length, capacity, Global) }
+    }
 }
 
 impl<T, A: Allocator> Vec<T, A> {
@@ -820,6 +831,22 @@ impl<T, A: Allocator> Vec<T, A> {
         unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
     }
 
+    /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts_in`].
+    ///
+    /// # Safety
+    ///
+    /// See [`Vec::from_raw_parts_in`].
+    #[inline]
+    #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling
+    pub(crate) unsafe fn from_nonnull_in(
+        ptr: NonNull<T>,
+        length: usize,
+        capacity: usize,
+        alloc: A,
+    ) -> Self {
+        unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
+    }
+
     /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`.
     ///
     /// Returns the raw pointer to the underlying data, the length of
diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs
index 33dd4139bc0..6646ae7bccb 100644
--- a/library/alloc/src/vec/spec_from_iter.rs
+++ b/library/alloc/src/vec/spec_from_iter.rs
@@ -51,7 +51,7 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
                 if has_advanced {
                     ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len());
                 }
-                return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
+                return Vec::from_nonnull(it.buf, it.len(), it.cap);
             }
         }
 
diff --git a/library/backtrace b/library/backtrace
-Subproject 6fa4b85b9962c3e1be8c2e5cc605cd078134152
+Subproject e15130618237eb3e2d4b622549f9647b4c1d9ca
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 44ae72bcd26..d448c5338fc 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -227,13 +227,10 @@ mod impls {
     impl_clone! {
         usize u8 u16 u32 u64 u128
         isize i8 i16 i32 i64 i128
-        f32 f64
+        f16 f32 f64 f128
         bool char
     }
 
-    #[cfg(not(bootstrap))]
-    impl_clone! { f16 f128 }
-
     #[unstable(feature = "never_type", issue = "35121")]
     impl Clone for ! {
         #[inline]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 81bba927554..fa218600ed9 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1497,12 +1497,9 @@ mod impls {
     }
 
     partial_eq_impl! {
-        bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
+        bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
     }
 
-    #[cfg(not(bootstrap))]
-    partial_eq_impl! { f16 f128 }
-
     macro_rules! eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
@@ -1553,10 +1550,7 @@ mod impls {
         }
     }
 
-    partial_ord_impl! { f32 f64 }
-
-    #[cfg(not(bootstrap))]
-    partial_ord_impl! { f16 f128 }
+    partial_ord_impl! { f16 f32 f64 f128 }
 
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index 0167d04c413..935ead2699a 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -34,8 +34,10 @@ macro_rules! impl_float_to_int {
     }
 }
 
+impl_float_to_int!(f16 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
 impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
 impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
+impl_float_to_int!(f128 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
 
 // Conversion traits for primitive integer and float types
 // Conversions T -> T are covered by a blanket impl and therefore excluded
@@ -163,7 +165,12 @@ impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
 impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 
 // float -> float
+// FIXME(f16_f128): adding additional `From` impls for existing types breaks inference. See
+// <https://github.com/rust-lang/rust/issues/123824>
+impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
+impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
+impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 
 macro_rules! impl_float_from_bool {
     ($float:ty) => {
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index dbdbaccb535..f4f33f8584b 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -517,8 +517,6 @@ impl CStr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(cstr_count_bytes)]
-    ///
     /// use std::ffi::CStr;
     ///
     /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
@@ -530,7 +528,7 @@ impl CStr {
     #[inline]
     #[must_use]
     #[doc(alias("len", "strlen"))]
-    #[unstable(feature = "cstr_count_bytes", issue = "114441")]
+    #[stable(feature = "cstr_count_bytes", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
     pub const fn count_bytes(&self) -> usize {
         self.inner.len() - 1
diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs
index 3bbf5d8770b..7f23d3c0956 100644
--- a/library/core/src/fmt/float.rs
+++ b/library/core/src/fmt/float.rs
@@ -228,3 +228,19 @@ macro_rules! floating {
 
 floating! { f32 }
 floating! { f64 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Debug for f16 {
+    #[inline]
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        write!(f, "{:#06x}", self.to_bits())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Debug for f128 {
+    #[inline]
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        write!(f, "{:#034x}", self.to_bits())
+    }
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 287f6c23c89..ce0643a3f5e 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -860,10 +860,10 @@ pub trait Binary {
 /// Basic usage with `i32`:
 ///
 /// ```
-/// let x = 42; // 42 is '2a' in hex
+/// let y = 42; // 42 is '2a' in hex
 ///
-/// assert_eq!(format!("{x:x}"), "2a");
-/// assert_eq!(format!("{x:#x}"), "0x2a");
+/// assert_eq!(format!("{y:x}"), "2a");
+/// assert_eq!(format!("{y:#x}"), "0x2a");
 ///
 /// assert_eq!(format!("{:x}", -16), "fffffff0");
 /// ```
@@ -915,10 +915,10 @@ pub trait LowerHex {
 /// Basic usage with `i32`:
 ///
 /// ```
-/// let x = 42; // 42 is '2A' in hex
+/// let y = 42; // 42 is '2A' in hex
 ///
-/// assert_eq!(format!("{x:X}"), "2A");
-/// assert_eq!(format!("{x:#X}"), "0x2A");
+/// assert_eq!(format!("{y:X}"), "2A");
+/// assert_eq!(format!("{y:#X}"), "0x2A");
 ///
 /// assert_eq!(format!("{:X}", -16), "FFFFFFF0");
 /// ```
@@ -1150,7 +1150,12 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
                 if !piece.is_empty() {
                     formatter.buf.write_str(*piece)?;
                 }
-                arg.fmt(&mut formatter)?;
+
+                // SAFETY: There are no formatting parameters and hence no
+                // count arguments.
+                unsafe {
+                    arg.fmt(&mut formatter)?;
+                }
                 idx += 1;
             }
         }
@@ -1198,7 +1203,8 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume
     let value = unsafe { args.get_unchecked(arg.position) };
 
     // Then actually do some printing
-    value.fmt(fmt)
+    // SAFETY: this is a placeholder argument.
+    unsafe { value.fmt(fmt) }
 }
 
 unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<usize> {
diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs
index cfb94cd9de5..a36e7efcd95 100644
--- a/library/core/src/fmt/nofloat.rs
+++ b/library/core/src/fmt/nofloat.rs
@@ -11,5 +11,7 @@ macro_rules! floating {
     };
 }
 
+floating! { f16 }
 floating! { f32 }
 floating! { f64 }
+floating! { f128 }
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index 5bf221b429f..5e4dac8f49b 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -4,6 +4,7 @@
 //! These are the lang items used by format_args!().
 
 use super::*;
+use crate::hint::unreachable_unchecked;
 
 #[lang = "format_placeholder"]
 #[derive(Copy, Clone)]
@@ -63,18 +64,26 @@ pub(super) enum Flag {
     DebugUpperHex,
 }
 
-/// This struct represents the generic "argument" which is taken by format_args!().
-/// It contains a function to format the given value. At compile time it is ensured that the
-/// function and the value have the correct types, and then this struct is used to canonicalize
-/// arguments to one type.
+#[derive(Copy, Clone)]
+enum ArgumentType<'a> {
+    Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result },
+    Count(usize),
+}
+
+/// This struct represents a generic "argument" which is taken by format_args!().
 ///
-/// Argument is essentially an optimized partially applied formatting function,
-/// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
+/// This can be either a placeholder argument or a count argument.
+/// * A placeholder argument contains a function to format the given value. At
+///   compile time it is ensured that the function and the value have the correct
+///   types, and then this struct is used to canonicalize arguments to one type.
+///   Placeholder arguments are essentially an optimized partially applied formatting
+///   function, equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
+/// * A count argument contains a count for dynamic formatting parameters like
+///   precision and width.
 #[lang = "format_argument"]
 #[derive(Copy, Clone)]
 pub struct Argument<'a> {
-    value: &'a Opaque,
-    formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
+    ty: ArgumentType<'a>,
 }
 
 #[rustc_diagnostic_item = "ArgumentMethods"]
@@ -89,7 +98,14 @@ impl<'a> Argument<'a> {
         // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
         // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
         // (as long as `T` is `Sized`)
-        unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } }
+        unsafe {
+            Argument {
+                ty: ArgumentType::Placeholder {
+                    formatter: mem::transmute(f),
+                    value: mem::transmute(x),
+                },
+            }
+        }
     }
 
     #[inline(always)]
@@ -130,30 +146,33 @@ impl<'a> Argument<'a> {
     }
     #[inline(always)]
     pub fn from_usize(x: &usize) -> Argument<'_> {
-        Self::new(x, USIZE_MARKER)
+        Argument { ty: ArgumentType::Count(*x) }
     }
 
+    /// Format this placeholder argument.
+    ///
+    /// # Safety
+    ///
+    /// This argument must actually be a placeholer argument.
+    ///
     // FIXME: Transmuting formatter in new and indirectly branching to/calling
     // it here is an explicit CFI violation.
     #[allow(inline_no_sanitize)]
     #[no_sanitize(cfi, kcfi)]
     #[inline(always)]
-    pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        (self.formatter)(self.value, f)
+    pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        match self.ty {
+            ArgumentType::Placeholder { formatter, value } => formatter(value, f),
+            // SAFETY: the caller promised this.
+            ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
+        }
     }
 
     #[inline(always)]
     pub(super) fn as_usize(&self) -> Option<usize> {
-        // We are type punning a bit here: USIZE_MARKER only takes an &usize but
-        // formatter takes an &Opaque. Rust understandably doesn't think we should compare
-        // the function pointers if they don't have the same signature, so we cast to
-        // usizes to tell it that we just want to compare addresses.
-        if self.formatter as usize == USIZE_MARKER as usize {
-            // SAFETY: The `formatter` field is only set to USIZE_MARKER if
-            // the value is a usize, so this is safe
-            Some(unsafe { *(self.value as *const _ as *const usize) })
-        } else {
-            None
+        match self.ty {
+            ArgumentType::Count(count) => Some(count),
+            ArgumentType::Placeholder { .. } => None,
         }
     }
 
@@ -193,24 +212,3 @@ impl UnsafeArg {
 extern "C" {
     type Opaque;
 }
-
-// This guarantees a single stable value for the function pointer associated with
-// indices/counts in the formatting infrastructure.
-//
-// Note that a function defined as such would not be correct as functions are
-// always tagged unnamed_addr with the current lowering to LLVM IR, so their
-// address is not considered important to LLVM and as such the as_usize cast
-// could have been miscompiled. In practice, we never call as_usize on non-usize
-// containing data (as a matter of static generation of the formatting
-// arguments), so this is merely an additional check.
-//
-// We primarily want to ensure that the function pointer at `USIZE_MARKER` has
-// an address corresponding *only* to functions that also take `&usize` as their
-// first argument. The read_volatile here ensures that we can safely ready out a
-// usize from the passed reference and that this address does not point at a
-// non-usize taking function.
-static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
-    // SAFETY: ptr is a reference
-    let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
-    loop {}
-};
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index 778d38b1537..81371708b51 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -249,9 +249,10 @@ impl<'a> BorrowedCursor<'a> {
     /// Panics if there are less than `n` bytes initialized.
     #[inline]
     pub fn advance(&mut self, n: usize) -> &mut Self {
-        assert!(self.buf.init >= self.buf.filled + n);
+        let filled = self.buf.filled.strict_add(n);
+        assert!(filled <= self.buf.init);
 
-        self.buf.filled += n;
+        self.buf.filled = filled;
         self
     }
 
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index d89801bce2b..2ebbe2bf274 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -150,6 +150,39 @@ pub trait FromIterator<A>: Sized {
     fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
 }
 
+/// This implementation turns an iterator of tuples into a tuple of types which implement
+/// [`Default`] and [`Extend`].
+///
+/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
+/// implementations:
+///
+/// ```rust
+/// # fn main() -> Result<(), core::num::ParseIntError> {
+/// let string = "1,2,123,4";
+///
+/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
+///     .split(',')
+///     .map(|s| s.parse().map(|n: u32| (n, s.len())))
+///     .collect::<Result<_, _>>()?;
+///
+/// assert_eq!(numbers, [1, 2, 123, 4]);
+/// assert_eq!(lengths, [1, 1, 3, 1]);
+/// # Ok(()) }
+/// ```
+#[stable(feature = "from_iterator_for_tuple", since = "CURRENT_RUSTC_VERSION")]
+impl<A, B, AE, BE> FromIterator<(AE, BE)> for (A, B)
+where
+    A: Default + Extend<AE>,
+    B: Default + Extend<BE>,
+{
+    fn from_iter<I: IntoIterator<Item = (AE, BE)>>(iter: I) -> Self {
+        let mut res = <(A, B)>::default();
+        res.extend(iter);
+
+        res
+    }
+}
+
 /// Conversion into an [`Iterator`].
 ///
 /// By implementing `IntoIterator` for a type, you define how it will be
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0ba3a557a03..d2618c8bb2b 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -111,6 +111,7 @@
 // tidy-alphabetical-start
 #![cfg_attr(bootstrap, feature(associated_type_bounds))]
 #![feature(array_ptr_get)]
+#![feature(asm_experimental_arch)]
 #![feature(char_indices_offset)]
 #![feature(const_align_of_val)]
 #![feature(const_align_of_val_raw)]
@@ -158,7 +159,6 @@
 #![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_slice_from_ref)]
 #![feature(const_slice_index)]
-#![feature(const_slice_ptr_len)]
 #![feature(const_slice_split_at_mut)]
 #![feature(const_str_from_utf8_unchecked_mut)]
 #![feature(const_strict_overflow_ops)]
@@ -200,8 +200,6 @@
 //
 // Language features:
 // tidy-alphabetical-start
-#![cfg_attr(not(bootstrap), feature(f128))]
-#![cfg_attr(not(bootstrap), feature(f16))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
@@ -226,6 +224,8 @@
 #![feature(doc_notable_trait)]
 #![feature(effects)]
 #![feature(extern_types)]
+#![feature(f128)]
+#![feature(f16)]
 #![feature(freeze_impls)]
 #![feature(fundamental)]
 #![feature(generic_arg_infer)]
@@ -347,6 +347,10 @@ pub mod u8;
 #[path = "num/shells/usize.rs"]
 pub mod usize;
 
+#[path = "num/f128.rs"]
+pub mod f128;
+#[path = "num/f16.rs"]
+pub mod f16;
 #[path = "num/f32.rs"]
 pub mod f32;
 #[path = "num/f64.rs"]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index fb97b3bfa09..1d073a6d649 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -422,17 +422,11 @@ marker_impls! {
     Copy for
         usize, u8, u16, u32, u64, u128,
         isize, i8, i16, i32, i64, i128,
-        f32, f64,
+        f16, f32, f64, f128,
         bool, char,
         {T: ?Sized} *const T,
         {T: ?Sized} *mut T,
-}
 
-#[cfg(not(bootstrap))]
-marker_impls! {
-    #[stable(feature = "rust1", since = "1.0.0")]
-    Copy for
-        f16, f128,
 }
 
 #[unstable(feature = "never_type", issue = "35121")]
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 55116285842..c24d8f55195 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -591,7 +591,7 @@ impl fmt::Display for SocketAddrV4 {
         if f.precision().is_none() && f.width().is_none() {
             write!(f, "{}:{}", self.ip(), self.port())
         } else {
-            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
+            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65535";
 
             let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
             // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
@@ -621,7 +621,7 @@ impl fmt::Display for SocketAddrV6 {
             }
         } else {
             const LONGEST_IPV6_SOCKET_ADDR: &str =
-                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
+                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967295]:65535";
 
             let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
             match self.scope_id() {
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
new file mode 100644
index 00000000000..8a94964c8c5
--- /dev/null
+++ b/library/core/src/num/f128.rs
@@ -0,0 +1,120 @@
+//! Constants for the `f128` quadruple-precision floating point type.
+//!
+//! *[See also the `f128` primitive type][f128].*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+//!
+//! For the constants defined directly in this module
+//! (as distinct from those defined in the `consts` sub-module),
+//! new code should instead use the associated constants
+//! defined directly on the `f128` type.
+
+#![unstable(feature = "f128", issue = "116909")]
+
+use crate::mem;
+
+/// Basic mathematical constants.
+#[unstable(feature = "f128", issue = "116909")]
+pub mod consts {}
+
+#[cfg(not(test))]
+impl f128 {
+    // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const
+    // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.
+
+    /// Returns `true` if this value is NaN.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
+    pub const fn is_nan(self) -> bool {
+        self != self
+    }
+
+    /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+    /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn is_sign_positive(self) -> bool {
+        !self.is_sign_negative()
+    }
+
+    /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+    /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn is_sign_negative(self) -> bool {
+        // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
+        // applies to zeros and NaNs as well.
+        // SAFETY: This is just transmuting to get the sign bit, it's fine.
+        (self.to_bits() & (1 << 127)) != 0
+    }
+
+    /// Raw transmutation to `u128`.
+    ///
+    /// This is currently identical to `transmute::<f128, u128>(self)` on all platforms.
+    ///
+    /// See [`from_bits`](#method.from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
+    /// Note that this function is distinct from `as` casting, which attempts to
+    /// preserve the *numeric* value, and not the bitwise value.
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    pub fn to_bits(self) -> u128 {
+        // SAFETY: `u128` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u128`.
+    ///
+    /// This is currently identical to `transmute::<u128, f128>(v)` on all platforms.
+    /// It turns out this is incredibly portable, for two reasons:
+    ///
+    /// * Floats and Ints have the same endianness on all supported platforms.
+    /// * IEEE 754 very precisely specifies the bit layout of floats.
+    ///
+    /// However there is one caveat: prior to the 2008 version of IEEE 754, how
+    /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+    /// (notably x86 and ARM) picked the interpretation that was ultimately
+    /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+    /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+    ///
+    /// Rather than trying to preserve signaling-ness cross-platform, this
+    /// implementation favors preserving the exact bits. This means that
+    /// any payloads encoded in NaNs will be preserved even if the result of
+    /// this method is sent over the network from an x86 machine to a MIPS one.
+    ///
+    /// If the results of this method are only manipulated by the same
+    /// architecture that produced them, then there is no portability concern.
+    ///
+    /// If the input isn't NaN, then there is no portability concern.
+    ///
+    /// If you don't care about signalingness (very likely), then there is no
+    /// portability concern.
+    ///
+    /// Note that this function is distinct from `as` casting, which attempts to
+    /// preserve the *numeric* value, and not the bitwise value.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn from_bits(v: u128) -> Self {
+        // SAFETY: `u128 is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        unsafe { mem::transmute(v) }
+    }
+}
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
new file mode 100644
index 00000000000..039f5188ba4
--- /dev/null
+++ b/library/core/src/num/f16.rs
@@ -0,0 +1,120 @@
+//! Constants for the `f16` half-precision floating point type.
+//!
+//! *[See also the `f16` primitive type][f16].*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+//!
+//! For the constants defined directly in this module
+//! (as distinct from those defined in the `consts` sub-module),
+//! new code should instead use the associated constants
+//! defined directly on the `f16` type.
+
+#![unstable(feature = "f16", issue = "116909")]
+
+use crate::mem;
+
+/// Basic mathematical constants.
+#[unstable(feature = "f16", issue = "116909")]
+pub mod consts {}
+
+#[cfg(not(test))]
+impl f16 {
+    // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const
+    // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.
+
+    /// Returns `true` if this value is NaN.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
+    pub const fn is_nan(self) -> bool {
+        self != self
+    }
+
+    /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+    /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn is_sign_positive(self) -> bool {
+        !self.is_sign_negative()
+    }
+
+    /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+    /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn is_sign_negative(self) -> bool {
+        // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
+        // applies to zeros and NaNs as well.
+        // SAFETY: This is just transmuting to get the sign bit, it's fine.
+        (self.to_bits() & (1 << 15)) != 0
+    }
+
+    /// Raw transmutation to `u16`.
+    ///
+    /// This is currently identical to `transmute::<f16, u16>(self)` on all platforms.
+    ///
+    /// See [`from_bits`](#method.from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
+    /// Note that this function is distinct from `as` casting, which attempts to
+    /// preserve the *numeric* value, and not the bitwise value.
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    pub fn to_bits(self) -> u16 {
+        // SAFETY: `u16` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u16`.
+    ///
+    /// This is currently identical to `transmute::<u16, f16>(v)` on all platforms.
+    /// It turns out this is incredibly portable, for two reasons:
+    ///
+    /// * Floats and Ints have the same endianness on all supported platforms.
+    /// * IEEE 754 very precisely specifies the bit layout of floats.
+    ///
+    /// However there is one caveat: prior to the 2008 version of IEEE 754, how
+    /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+    /// (notably x86 and ARM) picked the interpretation that was ultimately
+    /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+    /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+    ///
+    /// Rather than trying to preserve signaling-ness cross-platform, this
+    /// implementation favors preserving the exact bits. This means that
+    /// any payloads encoded in NaNs will be preserved even if the result of
+    /// this method is sent over the network from an x86 machine to a MIPS one.
+    ///
+    /// If the results of this method are only manipulated by the same
+    /// architecture that produced them, then there is no portability concern.
+    ///
+    /// If the input isn't NaN, then there is no portability concern.
+    ///
+    /// If you don't care about signalingness (very likely), then there is no
+    /// portability concern.
+    ///
+    /// Note that this function is distinct from `as` casting, which attempts to
+    /// preserve the *numeric* value, and not the bitwise value.
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "f16", issue = "116909")]
+    pub fn from_bits(v: u16) -> Self {
+        // SAFETY: `u16` is a plain old datatype so we can always... uh...
+        // ...look, just pretend you forgot what you just read.
+        // Stability concerns.
+        unsafe { mem::transmute(v) }
+    }
+}
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index fd50f804748..5e77788d8ea 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -109,7 +109,7 @@ macro_rules! add_impl {
     )*)
 }
 
-add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The subtraction operator `-`.
 ///
@@ -218,7 +218,7 @@ macro_rules! sub_impl {
     )*)
 }
 
-sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The multiplication operator `*`.
 ///
@@ -348,7 +348,7 @@ macro_rules! mul_impl {
     )*)
 }
 
-mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The division operator `/`.
 ///
@@ -506,7 +506,7 @@ macro_rules! div_impl_float {
     )*)
 }
 
-div_impl_float! { f32 f64 }
+div_impl_float! { f16 f32 f64 f128 }
 
 /// The remainder operator `%`.
 ///
@@ -623,7 +623,7 @@ macro_rules! rem_impl_float {
     )*)
 }
 
-rem_impl_float! { f32 f64 }
+rem_impl_float! { f16 f32 f64 f128 }
 
 /// The unary negation operator `-`.
 ///
@@ -698,7 +698,7 @@ macro_rules! neg_impl {
     )*)
 }
 
-neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 }
+neg_impl! { isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The addition assignment operator `+=`.
 ///
@@ -765,7 +765,7 @@ macro_rules! add_assign_impl {
     )+)
 }
 
-add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The subtraction assignment operator `-=`.
 ///
@@ -832,7 +832,7 @@ macro_rules! sub_assign_impl {
     )+)
 }
 
-sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The multiplication assignment operator `*=`.
 ///
@@ -890,7 +890,7 @@ macro_rules! mul_assign_impl {
     )+)
 }
 
-mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The division assignment operator `/=`.
 ///
@@ -947,7 +947,7 @@ macro_rules! div_assign_impl {
     )+)
 }
 
-div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 
 /// The remainder assignment operator `%=`.
 ///
@@ -1008,4 +1008,4 @@ macro_rules! rem_assign_impl {
     )+)
 }
 
-rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
+rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index e843a5d5790..efd525aeb3b 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -379,11 +379,11 @@
 //!
 //! Exposing access to the inner field which you want to remain pinned must then be carefully
 //! considered as well! Remember, exposing a method that gives access to a
-//! <code>[Pin]<[&mut] InnerT>></code> where `InnerT: [Unpin]` would allow safe code to trivially
-//! move the inner value out of that pinning pointer, which is precisely what you're seeking to
-//! prevent! Exposing a field of a pinned value through a pinning pointer is called "projecting"
-//! a pin, and the more general case of deciding in which cases a pin should be able to be
-//! projected or not is called "structural pinning." We will go into more detail about this
+//! <code>[Pin]<[&mut] InnerT>></code> where <code>InnerT: [Unpin]</code> would allow safe code to
+//! trivially move the inner value out of that pinning pointer, which is precisely what you're
+//! seeking to prevent! Exposing a field of a pinned value through a pinning pointer is called
+//! "projecting" a pin, and the more general case of deciding in which cases a pin should be able
+//! to be projected or not is called "structural pinning." We will go into more detail about this
 //! [below][structural-pinning].
 //!
 //! # Examples of address-sensitive types
@@ -1198,7 +1198,7 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> {
     /// Unwraps this `Pin<Ptr>`, returning the underlying pointer.
     ///
     /// Doing this operation safely requires that the data pointed at by this pinning pointer
-    /// implemts [`Unpin`] so that we can ignore the pinning invariants when unwrapping it.
+    /// implements [`Unpin`] so that we can ignore the pinning invariants when unwrapping it.
     ///
     /// # Examples
     ///
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 15da4171bda..e8e23f2a7ec 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1074,7 +1074,22 @@ mod prim_tuple {}
 #[doc(hidden)]
 impl<T> (T,) {}
 
+#[rustc_doc_primitive = "f16"]
+#[doc(alias = "half")]
+/// A 16-bit floating point type (specifically, the "binary16" type defined in IEEE 754-2008).
+///
+/// This type is very similar to [`prim@f32`] but has decreased precision because it uses half as many
+/// bits. Please see [the documentation for [`prim@f32`] or [Wikipedia on
+/// half-precision values][wikipedia] for more information.
+///
+/// *[See also the `std::f16::consts` module](crate::f16::consts).*
+///
+/// [wikipedia]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+#[unstable(feature = "f16", issue = "116909")]
+mod prim_f16 {}
+
 #[rustc_doc_primitive = "f32"]
+#[doc(alias = "single")]
 /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
 ///
 /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@@ -1143,6 +1158,7 @@ impl<T> (T,) {}
 mod prim_f32 {}
 
 #[rustc_doc_primitive = "f64"]
+#[doc(alias = "double")]
 /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`f32`], but has increased
@@ -1157,6 +1173,20 @@ mod prim_f32 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f64 {}
 
+#[rustc_doc_primitive = "f128"]
+#[doc(alias = "quad")]
+/// A 128-bit floating point type (specifically, the "binary128" type defined in IEEE 754-2008).
+///
+/// This type is very similar to [`prim@f32`] and [`prim@f64`], but has increased precision by using twice
+/// as many bits as `f64`. Please see [the documentation for [`prim@f32`] or [Wikipedia on
+/// quad-precision values][wikipedia] for more information.
+///
+/// *[See also the `std::f128::consts` module](crate::f128::consts).*
+///
+/// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
+#[unstable(feature = "f128", issue = "116909")]
+mod prim_f128 {}
+
 #[rustc_doc_primitive = "i8"]
 //
 /// The 8-bit signed integer type.
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 01db050e666..9737fb8816e 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1647,16 +1647,15 @@ impl<T> *const [T] {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_len)]
-    ///
     /// use std::ptr;
     ///
     /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
     /// assert_eq!(slice.len(), 3);
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_len", issue = "71146")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
@@ -1666,15 +1665,14 @@ impl<T> *const [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_ptr_len)]
     /// use std::ptr;
     ///
     /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
     /// assert!(!slice.is_empty());
     /// ```
     #[inline(always)]
-    #[unstable(feature = "slice_ptr_len", issue = "71146")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_empty(self) -> bool {
         self.len() == 0
     }
@@ -1804,7 +1802,7 @@ impl<T, const N: usize> *const [T; N] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(array_ptr_get, slice_ptr_len)]
+    /// #![feature(array_ptr_get)]
     ///
     /// let arr: *const [i32; 3] = &[1, 2, 4] as *const [i32; 3];
     /// let slice: *const [i32] = arr.as_slice();
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 41e5ba67458..08f03af355d 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1909,15 +1909,15 @@ impl<T> *mut [T] {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_len)]
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
     /// assert_eq!(slice.len(), 3);
     /// ```
     #[inline(always)]
-    #[unstable(feature = "slice_ptr_len", issue = "71146")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
@@ -1927,15 +1927,14 @@ impl<T> *mut [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_ptr_len)]
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
     /// assert!(!slice.is_empty());
     /// ```
     #[inline(always)]
-    #[unstable(feature = "slice_ptr_len", issue = "71146")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_empty(self) -> bool {
         self.len() == 0
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index f0e4b958bc6..96ce3cd3a3f 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1562,7 +1562,6 @@ impl<T> NonNull<[T]> {
     /// ```
     #[stable(feature = "slice_ptr_len_nonnull", since = "1.63.0")]
     #[rustc_const_stable(feature = "const_slice_ptr_len_nonnull", since = "1.63.0")]
-    #[rustc_allow_const_fn_unstable(const_slice_ptr_len)]
     #[must_use]
     #[inline]
     pub const fn len(self) -> usize {
@@ -1574,14 +1573,16 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_is_empty_nonnull)]
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
     /// assert!(!slice.is_empty());
     /// ```
-    #[unstable(feature = "slice_ptr_is_empty_nonnull", issue = "71146")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_is_empty_nonnull", issue = "71146")]
+    #[stable(feature = "slice_ptr_is_empty_nonnull", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(
+        feature = "const_slice_ptr_is_empty_nonnull",
+        since = "CURRENT_RUSTC_VERSION"
+    )]
     #[must_use]
     #[inline]
     pub const fn is_empty(self) -> bool {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 0c87860096f..e741149e7ce 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -54,7 +54,6 @@
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
-#![feature(slice_ptr_len)]
 #![feature(slice_split_once)]
 #![feature(split_as_slice)]
 #![feature(maybe_uninit_fill)]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index dde1c64c6f1..b0245de501e 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -19,6 +19,8 @@
 #![feature(panic_unwind)]
 #![feature(staged_api)]
 #![feature(std_internals)]
+#![feature(strict_provenance)]
+#![feature(exposed_provenance)]
 #![feature(rustc_attrs)]
 #![panic_runtime]
 #![feature(panic_runtime)]
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index e63749c77ce..6bc0559c88f 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -109,58 +109,88 @@ struct Exception {
 // [1]: https://www.geoffchappell.com/studies/msvc/language/predefined/
 
 #[cfg(target_arch = "x86")]
-#[macro_use]
 mod imp {
-    pub type ptr_t = *mut u8;
-
-    macro_rules! ptr {
-        (0) => {
-            core::ptr::null_mut()
-        };
-        ($e:expr) => {
-            $e as *mut u8
-        };
+    #[repr(transparent)]
+    #[derive(Copy, Clone)]
+    pub struct ptr_t(*mut u8);
+
+    impl ptr_t {
+        pub const fn null() -> Self {
+            Self(core::ptr::null_mut())
+        }
+
+        pub const fn new(ptr: *mut u8) -> Self {
+            Self(ptr)
+        }
+
+        pub const fn raw(self) -> *mut u8 {
+            self.0
+        }
     }
 }
 
 #[cfg(not(target_arch = "x86"))]
-#[macro_use]
 mod imp {
-    pub type ptr_t = u32;
+    use core::ptr::addr_of;
+
+    // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`.
+    #[repr(transparent)]
+    #[derive(Copy, Clone)]
+    pub struct ptr_t(u32);
 
     extern "C" {
         pub static __ImageBase: u8;
     }
 
-    macro_rules! ptr {
-        (0) => (0);
-        ($e:expr) => {
-            (($e as usize) - (addr_of!(imp::__ImageBase) as usize)) as u32
+    impl ptr_t {
+        pub const fn null() -> Self {
+            Self(0)
+        }
+
+        pub fn new(ptr: *mut u8) -> Self {
+            // We need to expose the provenance of the pointer because it is not carried by
+            // the `u32`, while the FFI needs to have this provenance to excess our statics.
+            //
+            // NOTE(niluxv): we could use `MaybeUninit<u32>` instead to leak the provenance
+            // into the FFI. In theory then the other side would need to do some processing
+            // to get a pointer with correct provenance, but these system functions aren't
+            // going to be cross-lang LTOed anyway. However, using expose is shorter and
+            // requires less unsafe.
+            let addr: usize = ptr.expose_provenance();
+            let image_base = unsafe { addr_of!(__ImageBase) }.addr();
+            let offset: usize = addr - image_base;
+            Self(offset as u32)
+        }
+
+        pub const fn raw(self) -> u32 {
+            self.0
         }
     }
 }
 
+use imp::ptr_t;
+
 #[repr(C)]
 pub struct _ThrowInfo {
     pub attributes: c_uint,
-    pub pmfnUnwind: imp::ptr_t,
-    pub pForwardCompat: imp::ptr_t,
-    pub pCatchableTypeArray: imp::ptr_t,
+    pub pmfnUnwind: ptr_t,
+    pub pForwardCompat: ptr_t,
+    pub pCatchableTypeArray: ptr_t,
 }
 
 #[repr(C)]
 pub struct _CatchableTypeArray {
     pub nCatchableTypes: c_int,
-    pub arrayOfCatchableTypes: [imp::ptr_t; 1],
+    pub arrayOfCatchableTypes: [ptr_t; 1],
 }
 
 #[repr(C)]
 pub struct _CatchableType {
     pub properties: c_uint,
-    pub pType: imp::ptr_t,
+    pub pType: ptr_t,
     pub thisDisplacement: _PMD,
     pub sizeOrOffset: c_int,
-    pub copyFunction: imp::ptr_t,
+    pub copyFunction: ptr_t,
 }
 
 #[repr(C)]
@@ -186,20 +216,20 @@ const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
 
 static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
     attributes: 0,
-    pmfnUnwind: ptr!(0),
-    pForwardCompat: ptr!(0),
-    pCatchableTypeArray: ptr!(0),
+    pmfnUnwind: ptr_t::null(),
+    pForwardCompat: ptr_t::null(),
+    pCatchableTypeArray: ptr_t::null(),
 };
 
 static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray =
-    _CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr!(0)] };
+    _CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr_t::null()] };
 
 static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
     properties: 0,
-    pType: ptr!(0),
+    pType: ptr_t::null(),
     thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
     sizeOrOffset: mem::size_of::<Exception>() as c_int,
-    copyFunction: ptr!(0),
+    copyFunction: ptr_t::null(),
 };
 
 extern "C" {
@@ -246,9 +276,9 @@ macro_rules! define_cleanup {
                 super::__rust_drop_panic();
             }
         }
-        unsafe extern $abi2 fn exception_copy(_dest: *mut Exception,
-                                             _src: *mut Exception)
-                                             -> *mut Exception {
+        unsafe extern $abi2 fn exception_copy(
+            _dest: *mut Exception, _src: *mut Exception
+        ) -> *mut Exception {
             panic!("Rust panics cannot be copied");
         }
     }
@@ -296,24 +326,24 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     // In any case, we basically need to do something like this until we can
     // express more operations in statics (and we may never be able to).
     atomic_store_seqcst(
-        addr_of_mut!(THROW_INFO.pmfnUnwind) as *mut u32,
-        ptr!(exception_cleanup) as u32,
+        addr_of_mut!(THROW_INFO.pmfnUnwind).cast(),
+        ptr_t::new(exception_cleanup as *mut u8).raw(),
     );
     atomic_store_seqcst(
-        addr_of_mut!(THROW_INFO.pCatchableTypeArray) as *mut u32,
-        ptr!(addr_of!(CATCHABLE_TYPE_ARRAY)) as u32,
+        addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(),
+        ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()).raw(),
     );
     atomic_store_seqcst(
-        addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]) as *mut u32,
-        ptr!(addr_of!(CATCHABLE_TYPE)) as u32,
+        addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(),
+        ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()).raw(),
     );
     atomic_store_seqcst(
-        addr_of_mut!(CATCHABLE_TYPE.pType) as *mut u32,
-        ptr!(addr_of!(TYPE_DESCRIPTOR)) as u32,
+        addr_of_mut!(CATCHABLE_TYPE.pType).cast(),
+        ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()).raw(),
     );
     atomic_store_seqcst(
-        addr_of_mut!(CATCHABLE_TYPE.copyFunction) as *mut u32,
-        ptr!(exception_copy) as u32,
+        addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(),
+        ptr_t::new(exception_copy as *mut u8).raw(),
     );
 
     extern "system-unwind" {
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index f3cfc41bac7..faca745e56f 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -283,7 +283,11 @@ fn maybe_install_panic_hook(force_show_panics: bool) {
     HIDE_PANICS_DURING_EXPANSION.call_once(|| {
         let prev = panic::take_hook();
         panic::set_hook(Box::new(move |info| {
-            if force_show_panics || !is_available() {
+            // We normally report panics by catching unwinds and passing the payload from the
+            // unwind back to the compiler, but if the panic doesn't unwind we'll abort before
+            // the compiler has a chance to print an error. So we special-case PanicInfo where
+            // can_unwind is false.
+            if force_show_panics || !is_available() || !info.can_unwind() {
                 prev(info)
             }
         }));
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 01c449563ee..a3ebef45c88 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -30,6 +30,7 @@
 #![feature(maybe_uninit_write_slice)]
 #![feature(negative_impls)]
 #![feature(new_uninit)]
+#![feature(panic_can_unwind)]
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
new file mode 100644
index 00000000000..4710d7c50b4
--- /dev/null
+++ b/library/std/src/f128.rs
@@ -0,0 +1,11 @@
+//! Constants for the `f128` double-precision floating point type.
+//!
+//! *[See also the `f128` primitive type](primitive@f128).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+
+#[cfg(test)]
+mod tests;
+
+#[unstable(feature = "f128", issue = "116909")]
+pub use core::f128::consts;
diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs
new file mode 100644
index 00000000000..b64c7f856a1
--- /dev/null
+++ b/library/std/src/f128/tests.rs
@@ -0,0 +1,40 @@
+#![allow(dead_code)] // FIXME(f16_f128): remove once constants are used
+
+/// Smallest number
+const TINY_BITS: u128 = 0x1;
+/// Next smallest number
+const TINY_UP_BITS: u128 = 0x2;
+/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0
+const MAX_DOWN_BITS: u128 = 0x7ffeffffffffffffffffffffffffffff;
+/// Zeroed exponent, full significant
+const LARGEST_SUBNORMAL_BITS: u128 = 0x0000ffffffffffffffffffffffffffff;
+/// Exponent = 0b1, zeroed significand
+const SMALLEST_NORMAL_BITS: u128 = 0x00010000000000000000000000000000;
+/// First pattern over the mantissa
+const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+/// Second pattern over the mantissa
+const NAN_MASK2: u128 = 0x00005555555555555555555555555555;
+
+/// Compare by value
+#[allow(unused_macros)]
+macro_rules! assert_f128_eq {
+    ($a:expr, $b:expr) => {
+        let (l, r): (&f128, &f128) = (&$a, &$b);
+        assert_eq!(*l, *r, "\na: {:#0130x}\nb: {:#0130x}", l.to_bits(), r.to_bits())
+    };
+}
+
+/// Compare by representation
+#[allow(unused_macros)]
+macro_rules! assert_f128_biteq {
+    ($a:expr, $b:expr) => {
+        let (l, r): (&f128, &f128) = (&$a, &$b);
+        let lb = l.to_bits();
+        let rb = r.to_bits();
+        assert_eq!(
+            lb, rb,
+            "float {:?} is not bitequal to {:?}.\na: {:#0130x}\nb: {:#0130x}",
+            *l, *r, lb, rb
+        );
+    };
+}
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
new file mode 100644
index 00000000000..c36f9f5d4c6
--- /dev/null
+++ b/library/std/src/f16.rs
@@ -0,0 +1,11 @@
+//! Constants for the `f16` double-precision floating point type.
+//!
+//! *[See also the `f16` primitive type](primitive@f16).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+
+#[cfg(test)]
+mod tests;
+
+#[unstable(feature = "f16", issue = "116909")]
+pub use core::f16::consts;
diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs
new file mode 100644
index 00000000000..d65c43eca4b
--- /dev/null
+++ b/library/std/src/f16/tests.rs
@@ -0,0 +1,46 @@
+#![allow(dead_code)] // FIXME(f16_f128): remove once constants are used
+
+// We run out of precision pretty quickly with f16
+const F16_APPROX_L1: f16 = 0.001;
+const F16_APPROX_L2: f16 = 0.01;
+const F16_APPROX_L3: f16 = 0.1;
+const F16_APPROX_L4: f16 = 0.5;
+
+/// Smallest number
+const TINY_BITS: u16 = 0x1;
+/// Next smallest number
+const TINY_UP_BITS: u16 = 0x2;
+/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0
+const MAX_DOWN_BITS: u16 = 0x7bfe;
+/// Zeroed exponent, full significant
+const LARGEST_SUBNORMAL_BITS: u16 = 0x03ff;
+/// Exponent = 0b1, zeroed significand
+const SMALLEST_NORMAL_BITS: u16 = 0x0400;
+/// First pattern over the mantissa
+const NAN_MASK1: u16 = 0x02aa;
+/// Second pattern over the mantissa
+const NAN_MASK2: u16 = 0x0155;
+
+/// Compare by value
+#[allow(unused_macros)]
+macro_rules! assert_f16_eq {
+    ($a:expr, $b:expr) => {
+        let (l, r): (&f16, &f16) = (&$a, &$b);
+        assert_eq!(*l, *r, "\na: {:#018x}\nb: {:#018x}", l.to_bits(), r.to_bits())
+    };
+}
+
+/// Compare by representation
+#[allow(unused_macros)]
+macro_rules! assert_f16_biteq {
+    ($a:expr, $b:expr) => {
+        let (l, r): (&f16, &f16) = (&$a, &$b);
+        let lb = l.to_bits();
+        let rb = r.to_bits();
+        assert_eq!(
+            lb, rb,
+            "float {:?} is not bitequal to {:?}.\na: {:#018x}\nb: {:#018x}",
+            *l, *r, lb, rb
+        );
+    };
+}
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index b1102b440e0..1b8fafd0089 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -465,14 +465,20 @@ impl File {
         OpenOptions::new()
     }
 
-    /// Attempts to sync all OS-internal metadata to disk.
+    /// Attempts to sync all OS-internal file content and metadata to disk.
     ///
     /// This function will attempt to ensure that all in-memory data reaches the
     /// filesystem before returning.
     ///
     /// This can be used to handle errors that would otherwise only be caught
-    /// when the `File` is closed.  Dropping a file will ignore errors in
-    /// synchronizing this in-memory data.
+    /// when the `File` is closed, as dropping a `File` will ignore all errors.
+    /// Note, however, that `sync_all` is generally more expensive than closing
+    /// a file by dropping it, because the latter is not required to block until
+    /// the data has been written to the filesystem.
+    ///
+    /// If synchronizing the metadata is not required, use [`sync_data`] instead.
+    ///
+    /// [`sync_data`]: File::sync_data
     ///
     /// # Examples
     ///
@@ -489,6 +495,7 @@ impl File {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(alias = "fsync")]
     pub fn sync_all(&self) -> io::Result<()> {
         self.inner.fsync()
     }
@@ -520,6 +527,7 @@ impl File {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(alias = "fdatasync")]
     pub fn sync_data(&self) -> io::Result<()> {
         self.inner.datasync()
     }
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 250cd583696..0cdc49c87d8 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -383,12 +383,7 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
             // buffer.
             let mut bytes = Vec::new();
             self.read_to_end(&mut bytes)?;
-            let string = crate::str::from_utf8(&bytes).map_err(|_| {
-                io::const_io_error!(
-                    io::ErrorKind::InvalidData,
-                    "stream did not contain valid UTF-8",
-                )
-            })?;
+            let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?;
             *buf += string;
             Ok(string.len())
         }
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 85625116d02..4e1d7c2ac65 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -75,6 +75,30 @@ impl fmt::Debug for Error {
     }
 }
 
+/// Common errors constants for use in std
+#[allow(dead_code)]
+impl Error {
+    pub(crate) const INVALID_UTF8: Self =
+        const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
+
+    pub(crate) const READ_EXACT_EOF: Self =
+        const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
+
+    pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_io_error!(
+        ErrorKind::NotFound,
+        "The number of hardware threads is not known for the target platform"
+    );
+
+    pub(crate) const UNSUPPORTED_PLATFORM: Self =
+        const_io_error!(ErrorKind::Unsupported, "operation not supported on this platform");
+
+    pub(crate) const WRITE_ALL_EOF: Self =
+        const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer");
+
+    pub(crate) const ZERO_TIMEOUT: Self =
+        const_io_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<alloc::ffi::NulError> for Error {
     /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index ee7ed4bcc9a..dd7e0725176 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -5,9 +5,7 @@ use crate::alloc::Allocator;
 use crate::cmp;
 use crate::collections::VecDeque;
 use crate::fmt;
-use crate::io::{
-    self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
-};
+use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
 use crate::mem;
 use crate::str;
 
@@ -289,10 +287,7 @@ impl Read for &[u8] {
     #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
-            return Err(io::const_io_error!(
-                ErrorKind::UnexpectedEof,
-                "failed to fill whole buffer"
-            ));
+            return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(buf.len());
 
@@ -312,10 +307,7 @@ impl Read for &[u8] {
     #[inline]
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         if cursor.capacity() > self.len() {
-            return Err(io::const_io_error!(
-                ErrorKind::UnexpectedEof,
-                "failed to fill whole buffer"
-            ));
+            return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(cursor.capacity());
 
@@ -336,9 +328,7 @@ impl Read for &[u8] {
 
     #[inline]
     fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
-        let content = str::from_utf8(self).map_err(|_| {
-            io::const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8")
-        })?;
+        let content = str::from_utf8(self).map_err(|_| io::Error::INVALID_UTF8)?;
         buf.push_str(content);
         let len = self.len();
         *self = &self[len..];
@@ -399,11 +389,7 @@ impl Write for &mut [u8] {
 
     #[inline]
     fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
-        if self.write(data)? == data.len() {
-            Ok(())
-        } else {
-            Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"))
-        }
+        if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) }
     }
 
     #[inline]
@@ -491,9 +477,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
         // middle of an UTF-8 character.
         let len = self.len();
         let content = self.make_contiguous();
-        let string = str::from_utf8(content).map_err(|_| {
-            io::const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8")
-        })?;
+        let string = str::from_utf8(content).map_err(|_| io::Error::INVALID_UTF8)?;
         buf.push_str(string);
         self.clear();
         Ok(len)
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 980b3e7aa48..98973a43e1d 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -311,14 +311,14 @@ pub use self::buffered::WriterPanicked;
 #[unstable(feature = "raw_os_error_ty", issue = "107792")]
 pub use self::error::RawOsError;
 pub(crate) use self::stdio::attempt_print_to_stderr;
-#[unstable(feature = "internal_output_capture", issue = "none")]
-#[doc(no_inline, hidden)]
-pub use self::stdio::set_output_capture;
 #[stable(feature = "is_terminal", since = "1.70.0")]
 pub use self::stdio::IsTerminal;
 #[unstable(feature = "print_internals", issue = "none")]
 #[doc(hidden)]
 pub use self::stdio::{_eprint, _print};
+#[unstable(feature = "internal_output_capture", issue = "none")]
+#[doc(no_inline, hidden)]
+pub use self::stdio::{set_output_capture, try_set_output_capture};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::{
     buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
@@ -385,12 +385,7 @@ where
     let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
     let ret = f(g.buf);
     if str::from_utf8(&g.buf[g.len..]).is_err() {
-        ret.and_then(|_| {
-            Err(error::const_io_error!(
-                ErrorKind::InvalidData,
-                "stream did not contain valid UTF-8"
-            ))
-        })
+        ret.and_then(|_| Err(Error::INVALID_UTF8))
     } else {
         g.len = g.buf.len();
         ret
@@ -566,11 +561,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
             Err(e) => return Err(e),
         }
     }
-    if !buf.is_empty() {
-        Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
-    } else {
-        Ok(())
-    }
+    if !buf.is_empty() { Err(Error::READ_EXACT_EOF) } else { Ok(()) }
 }
 
 pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()>
@@ -595,10 +586,7 @@ pub(crate) fn default_read_buf_exact<R: Read + ?Sized>(
         }
 
         if cursor.written() == prev_written {
-            return Err(error::const_io_error!(
-                ErrorKind::UnexpectedEof,
-                "failed to fill whole buffer"
-            ));
+            return Err(Error::READ_EXACT_EOF);
         }
     }
 
@@ -1709,10 +1697,7 @@ pub trait Write {
         while !buf.is_empty() {
             match self.write(buf) {
                 Ok(0) => {
-                    return Err(error::const_io_error!(
-                        ErrorKind::WriteZero,
-                        "failed to write whole buffer",
-                    ));
+                    return Err(Error::WRITE_ALL_EOF);
                 }
                 Ok(n) => buf = &buf[n..],
                 Err(ref e) if e.is_interrupted() => {}
@@ -1777,10 +1762,7 @@ pub trait Write {
         while !bufs.is_empty() {
             match self.write_vectored(bufs) {
                 Ok(0) => {
-                    return Err(error::const_io_error!(
-                        ErrorKind::WriteZero,
-                        "failed to write whole buffer",
-                    ));
+                    return Err(Error::WRITE_ALL_EOF);
                 }
                 Ok(n) => IoSlice::advance_slices(&mut bufs, n),
                 Err(ref e) if e.is_interrupted() => {}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 73fa7cbc3fe..07fa9259e0b 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -15,6 +15,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard};
 use crate::sys::stdio;
+use crate::thread::AccessError;
 
 type LocalStream = Arc<Mutex<Vec<u8>>>;
 
@@ -1064,12 +1065,31 @@ impl fmt::Debug for StderrLock<'_> {
 )]
 #[doc(hidden)]
 pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
+    try_set_output_capture(sink).expect(
+        "cannot access a Thread Local Storage value \
+         during or after destruction",
+    )
+}
+
+/// Tries to set the thread-local output capture buffer and returns the old one.
+/// This may fail once thread-local destructors are called. It's used in panic
+/// handling instead of `set_output_capture`.
+#[unstable(
+    feature = "internal_output_capture",
+    reason = "this function is meant for use in the test crate \
+    and may disappear in the future",
+    issue = "none"
+)]
+#[doc(hidden)]
+pub fn try_set_output_capture(
+    sink: Option<LocalStream>,
+) -> Result<Option<LocalStream>, AccessError> {
     if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
         // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
-        return None;
+        return Ok(None);
     }
     OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
-    OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
+    OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink))
 }
 
 /// Write `args` to the capture buffer if enabled and possible, or `global_s`
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index eb5d5988768..090a091b09a 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -210,6 +210,15 @@ fn read_buf_exact() {
 }
 
 #[test]
+#[should_panic]
+fn borrowed_cursor_advance_overflow() {
+    let mut buf = [0; 512];
+    let mut buf = BorrowedBuf::from(&mut buf[..]);
+    buf.unfilled().advance(1);
+    buf.unfilled().advance(usize::MAX);
+}
+
+#[test]
 fn take_eof() {
     struct R;
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index c713eefc72c..e9de3b77670 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -214,7 +214,16 @@
 //! [slice]: prim@slice
 
 #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
-#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
+#![cfg_attr(
+    feature = "restricted-std",
+    unstable(
+        feature = "restricted_std",
+        issue = "none",
+        reason = "You have attempted to use a standard library built for a platform that it doesn't \
+            know how to support. Consider building it for a known environment, disabling it with \
+            `#![no_std]` or overriding this warning by enabling this feature."
+    )
+)]
 #![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)]
 #![doc(
     html_playground_url = "https://play.rust-lang.org/",
@@ -256,7 +265,6 @@
     feature(slice_index_methods, coerce_unsized, sgx_platform)
 )]
 #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))]
-#![cfg_attr(target_os = "xous", feature(slice_ptr_len))]
 #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))]
 #![cfg_attr(
     all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"),
@@ -283,6 +291,8 @@
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
+#![feature(f128)]
+#![feature(f16)]
 #![feature(if_let_guard)]
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
@@ -558,6 +568,10 @@ pub use core::u8;
 #[allow(deprecated, deprecated_in_future)]
 pub use core::usize;
 
+#[unstable(feature = "f128", issue = "116909")]
+pub mod f128;
+#[unstable(feature = "f16", issue = "116909")]
+pub mod f16;
 pub mod f32;
 pub mod f64;
 
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 0b3c5153871..010ce4e5076 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -117,10 +117,7 @@ impl BorrowedFd<'_> {
     #[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
-        Err(crate::io::const_io_error!(
-            crate::io::ErrorKind::Unsupported,
-            "operation not supported on this platform",
-        ))
+        Err(crate::io::Error::UNSUPPORTED_PLATFORM)
     }
 }
 
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 058e9b90cc7..970023d8cf1 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -127,11 +127,7 @@ pub trait FileExt {
                 Err(e) => return Err(e),
             }
         }
-        if !buf.is_empty() {
-            Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
-        } else {
-            Ok(())
-        }
+        if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
     }
 
     /// Writes a number of bytes starting from a given offset.
@@ -249,10 +245,7 @@ pub trait FileExt {
         while !buf.is_empty() {
             match self.write_at(buf, offset) {
                 Ok(0) => {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::WriteZero,
-                        "failed to write whole buffer",
-                    ));
+                    return Err(io::Error::WRITE_ALL_EOF);
                 }
                 Ok(n) => {
                     buf = &buf[n..];
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 9757653e02c..1787eba0ef8 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -107,6 +107,16 @@ impl SocketAddr {
         addr: libc::sockaddr_un,
         mut len: libc::socklen_t,
     ) -> io::Result<SocketAddr> {
+        if cfg!(target_os = "openbsd") {
+            // on OpenBSD, getsockname(2) returns the actual size of the socket address,
+            // and not the len of the content. Figure out the length for ourselves.
+            // https://marc.info/?l=openbsd-bugs&m=170105481926736&w=2
+            let sun_path: &[u8] =
+                unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) };
+            len = core::slice::memchr::memchr(0, sun_path)
+                .map_or(len, |new_len| (new_len + sun_path_offset(&addr)) as libc::socklen_t);
+        }
+
         if len == 0 {
             // When there is a datagram from unnamed unix socket
             // linux returns zero bytes of address
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 4525c3aa914..46fc2a50de9 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -86,11 +86,7 @@ pub trait FileExt {
                 Err(e) => return Err(e),
             }
         }
-        if !buf.is_empty() {
-            Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
-        } else {
-            Ok(())
-        }
+        if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
     }
 
     /// Writes a number of bytes starting from a given offset.
@@ -153,10 +149,7 @@ pub trait FileExt {
         while !buf.is_empty() {
             match self.write_at(buf, offset) {
                 Ok(0) => {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::WriteZero,
-                        "failed to write whole buffer",
-                    ));
+                    return Err(io::Error::WRITE_ALL_EOF);
                 }
                 Ok(n) => {
                     buf = &buf[n..];
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index f46e1e171d2..0052fcbb94a 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -24,11 +24,11 @@ use crate::sys_common::backtrace;
 use crate::thread;
 
 #[cfg(not(test))]
-use crate::io::set_output_capture;
+use crate::io::try_set_output_capture;
 // make sure to use the stderr output configured
 // by libtest in the real copy of std
 #[cfg(test)]
-use realstd::io::set_output_capture;
+use realstd::io::try_set_output_capture;
 
 // Binary interface to the panic runtime that the standard library depends on.
 //
@@ -284,9 +284,9 @@ fn default_hook(info: &PanicInfo<'_>) {
         }
     };
 
-    if let Some(local) = set_output_capture(None) {
+    if let Ok(Some(local)) = try_set_output_capture(None) {
         write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
-        set_output_capture(Some(local));
+        try_set_output_capture(Some(local)).ok();
     } else if let Some(mut out) = panic_output() {
         write(&mut out);
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 56ea51226f9..5f43d63bf84 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2143,10 +2143,10 @@ impl Path {
     /// # Examples
     ///
     /// ```
-    /// use std::path::Path;
+    /// use std::path::{Path, PathBuf};
     ///
     /// let path_buf = Path::new("foo.txt").to_path_buf();
-    /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
+    /// assert_eq!(path_buf, PathBuf::from("foo.txt"));
     /// ```
     #[rustc_conversion_suggestion]
     #[must_use = "this returns the result of the operation, \
@@ -2278,10 +2278,9 @@ impl Path {
     /// Produces an iterator over `Path` and its ancestors.
     ///
     /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
-    /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
-    /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
-    /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
-    /// namely `&self`.
+    /// or more times. If the [`parent`] method returns [`None`], the iterator will do likewise.
+    /// The iterator will always yield at least one value, namely `Some(&self)`. Next it will yield
+    /// `&self.parent()`, `&self.parent().and_then(Path::parent)` and so on.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 1c53796f5d4..23ac71cb9f2 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -80,10 +80,7 @@ impl Socket {
         let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::const_io_error!(
-                io::ErrorKind::InvalidInput,
-                "cannot set a 0 duration timeout",
-            ));
+            return Err(io::Error::ZERO_TIMEOUT);
         }
 
         let start = Instant::now();
@@ -245,10 +242,7 @@ impl Socket {
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
+                    return Err(io::Error::ZERO_TIMEOUT);
                 }
 
                 let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs
index edb28e2300f..68a2d5eded2 100644
--- a/library/std/src/sys/pal/sgx/net.rs
+++ b/library/std/src/sys/pal/sgx/net.rs
@@ -97,10 +97,7 @@ impl TcpStream {
 
     pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
         if dur == Duration::default() {
-            return Err(io::const_io_error!(
-                io::ErrorKind::InvalidInput,
-                "cannot set a 0 duration timeout",
-            ));
+            return Err(io::Error::ZERO_TIMEOUT);
         }
         Self::connect(Ok(addr)) // FIXME: ignoring timeout
     }
@@ -108,10 +105,7 @@ impl TcpStream {
     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
         match dur {
             Some(dur) if dur == Duration::default() => {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    "cannot set a 0 duration timeout",
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
             _ => sgx_ineffective(()),
         }
@@ -120,10 +114,7 @@ impl TcpStream {
     pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
         match dur {
             Some(dur) if dur == Duration::default() => {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    "cannot set a 0 duration timeout",
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
             _ => sgx_ineffective(()),
         }
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 109ee1a0ab6..3f6ff37903a 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -50,10 +50,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> {
 }
 
 pub fn unsupported_err() -> crate::io::Error {
-    crate::io::const_io_error!(
-        crate::io::ErrorKind::Unsupported,
-        "operation not supported on this platform",
-    )
+    crate::io::Error::UNSUPPORTED_PLATFORM
 }
 
 #[inline]
diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs
index 6ea874e509e..5bd339849e9 100644
--- a/library/std/src/sys/pal/solid/net.rs
+++ b/library/std/src/sys/pal/solid/net.rs
@@ -154,10 +154,7 @@ impl Socket {
         }
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::const_io_error!(
-                io::ErrorKind::InvalidInput,
-                "cannot set a 0 duration timeout",
-            ));
+            return Err(io::Error::ZERO_TIMEOUT);
         }
 
         let mut timeout =
@@ -306,10 +303,7 @@ impl Socket {
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
+                    return Err(io::Error::ZERO_TIMEOUT);
                 }
 
                 let secs = if dur.as_secs() > netc::c_long::MAX as u64 {
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index ae2f58ca08e..f4723b2ea46 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -141,10 +141,7 @@ impl Drop for Thread {
 // Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
 // teeos, so this function always returns an Error!
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    Err(io::Error::new(
-        io::ErrorKind::NotFound,
-        "The number of hardware threads is not known for the target platform",
-    ))
+    Err(io::Error::UNKNOWN_THREAD_COUNT)
 }
 
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 4ae76518c4f..3ef43a923a3 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -433,6 +433,6 @@ mod unsupported {
     }
 
     pub fn unsupported_err() -> io::Error {
-        io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
+        io::Error::UNSUPPORTED_PLATFORM
     }
 }
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index 9a0a1b18aee..7237989c905 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -175,10 +175,7 @@ impl Socket {
         let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::const_io_error!(
-                io::ErrorKind::InvalidInput,
-                "cannot set a 0 duration timeout",
-            ));
+            return Err(io::Error::ZERO_TIMEOUT);
         }
 
         let start = Instant::now();
@@ -360,10 +357,7 @@ impl Socket {
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
+                    return Err(io::Error::ZERO_TIMEOUT);
                 }
 
                 let secs = if dur.as_secs() > libc::time_t::MAX as u64 {
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index c550cc04a39..6a6bfc77a85 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -356,7 +356,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             }
             match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
                 -1 => Err(io::Error::last_os_error()),
-                0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
+                0 => Err(io::Error::UNKNOWN_THREAD_COUNT),
                 cpus => {
                     let count = cpus as usize;
                     // Cover the unusual situation where we were able to get the quota but not the affinity mask
@@ -439,7 +439,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 if res == -1 {
                     return Err(io::Error::last_os_error());
                 } else if cpus == 0 {
-                    return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
+                    return Err(io::Error::UNKNOWN_THREAD_COUNT);
                 }
             }
 
@@ -452,13 +452,13 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 } else {
                     let cpus = (*_syspage_ptr).num_cpu;
                     NonZero::new(cpus as usize)
-                        .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
+                        .ok_or(io::Error::UNKNOWN_THREAD_COUNT)
                 }
             }
         } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
             let mut cpus = 0u32;
             if unsafe { libc::pset_info(libc::PS_MYID, core::ptr::null_mut(), &mut cpus, core::ptr::null_mut()) } != 0 {
-                return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
+                return Err(io::Error::UNKNOWN_THREAD_COUNT);
             }
             Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
         } else if #[cfg(target_os = "haiku")] {
@@ -469,7 +469,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 let res = libc::get_system_info(&mut sinfo);
 
                 if res != libc::B_OK {
-                    return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
+                    return Err(io::Error::UNKNOWN_THREAD_COUNT);
                 }
 
                 Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs
index 4f44db610af..76f80291f0e 100644
--- a/library/std/src/sys/pal/unsupported/common.rs
+++ b/library/std/src/sys/pal/unsupported/common.rs
@@ -13,10 +13,7 @@ pub fn unsupported<T>() -> std_io::Result<T> {
 }
 
 pub fn unsupported_err() -> std_io::Error {
-    std_io::const_io_error!(
-        std_io::ErrorKind::Unsupported,
-        "operation not supported on this platform",
-    )
+    std_io::Error::UNSUPPORTED_PLATFORM
 }
 
 pub fn is_interrupted(_code: i32) -> bool {
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index 1e6169ea8ec..9e15b15a351 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -154,10 +154,7 @@ impl Socket {
         match result {
             Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
                 if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
+                    return Err(io::Error::ZERO_TIMEOUT);
                 }
 
                 let mut timeout = c::timeval {
@@ -364,10 +361,7 @@ impl Socket {
             Some(dur) => {
                 let timeout = sys::dur2timeout(dur);
                 if timeout == 0 {
-                    return Err(io::const_io_error!(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
+                    return Err(io::Error::ZERO_TIMEOUT);
                 }
                 timeout
             }
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 9b1c5b34bbf..70099e0a3b5 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -45,13 +45,11 @@ impl Thread {
             Err(io::Error::last_os_error())
         };
 
-        extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
-            unsafe {
-                // Next, reserve some stack space for if we otherwise run out of stack.
-                stack_overflow::reserve_stack();
-                // Finally, let's run some code.
-                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
-            }
+        unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
+            // Next, reserve some stack space for if we otherwise run out of stack.
+            stack_overflow::reserve_stack();
+            // Finally, let's run some code.
+            Box::from_raw(main as *mut Box<dyn FnOnce()>)();
             0
         }
     }
@@ -59,15 +57,19 @@ impl Thread {
     pub fn set_name(name: &CStr) {
         if let Ok(utf8) = name.to_str() {
             if let Ok(utf16) = to_u16s(utf8) {
-                Self::set_name_wide(&utf16)
+                unsafe {
+                    // SAFETY: the vec returned by `to_u16s` ends with a zero value
+                    Self::set_name_wide(&utf16)
+                }
             };
         };
     }
 
-    pub fn set_name_wide(name: &[u16]) {
-        unsafe {
-            c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr());
-        };
+    /// # Safety
+    ///
+    /// `name` must end with a zero value
+    pub unsafe fn set_name_wide(name: &[u16]) {
+        c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr());
     }
 
     pub fn join(self) {
@@ -116,10 +118,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
         sysinfo.dwNumberOfProcessors as usize
     };
     match res {
-        0 => Err(io::const_io_error!(
-            io::ErrorKind::NotFound,
-            "The number of hardware threads is not known for the target platform",
-        )),
+        0 => Err(io::Error::UNKNOWN_THREAD_COUNT),
         cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/pal/xous/net/tcpstream.rs
index aebef02acda..0ad88110711 100644
--- a/library/std/src/sys/pal/xous/net/tcpstream.rs
+++ b/library/std/src/sys/pal/xous/net/tcpstream.rs
@@ -140,10 +140,7 @@ impl TcpStream {
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         if let Some(to) = timeout {
             if to.is_zero() {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    &"Zero is an invalid timeout",
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
         }
         self.read_timeout.store(
@@ -156,10 +153,7 @@ impl TcpStream {
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         if let Some(to) = timeout {
             if to.is_zero() {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    &"Zero is an invalid timeout",
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
         }
         self.write_timeout.store(
diff --git a/library/std/src/sys/pal/xous/net/udp.rs b/library/std/src/sys/pal/xous/net/udp.rs
index cafa5b3bde8..3d0522b25f3 100644
--- a/library/std/src/sys/pal/xous/net/udp.rs
+++ b/library/std/src/sys/pal/xous/net/udp.rs
@@ -331,10 +331,7 @@ impl UdpSocket {
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         if let Some(d) = timeout {
             if d.is_zero() {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    &"Zero duration is invalid"
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
         }
         self.read_timeout
@@ -345,10 +342,7 @@ impl UdpSocket {
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         if let Some(d) = timeout {
             if d.is_zero() {
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidInput,
-                    &"Zero duration is invalid"
-                ));
+                return Err(io::Error::ZERO_TIMEOUT);
             }
         }
         self.write_timeout
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 228a976dbab..4f79f8c4961 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -12,8 +12,6 @@ const WORD_SIZE: usize = core::mem::size_of::<u32>();
 pub mod alloc;
 #[path = "../zkvm/args.rs"]
 pub mod args;
-#[path = "../unix/cmath.rs"]
-pub mod cmath;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
@@ -54,10 +52,7 @@ pub fn unsupported<T>() -> std_io::Result<T> {
 }
 
 pub fn unsupported_err() -> std_io::Error {
-    std_io::const_io_error!(
-        std_io::ErrorKind::Unsupported,
-        "operation not supported on this platform",
-    )
+    std_io::Error::UNSUPPORTED_PLATFORM
 }
 
 pub fn is_interrupted(_code: i32) -> bool {
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 5abf201aa20..cc21560fff5 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -25,7 +25,6 @@ pub mod fs;
 pub mod io;
 pub mod lazy_box;
 pub mod process;
-pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_parking;
 pub mod wstr;
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 8c9885974b4..6a268633f72 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -417,6 +417,10 @@ impl TcpListener {
                 // it allows up to about 37, but other times it doesn't even
                 // accept 32. There may be a global limitation causing this.
                 let backlog = 20;
+            } else if #[cfg(target_os = "haiku")] {
+                // Haiku does not support a queue length > 32
+                // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81
+                let backlog = 32;
             } else {
                 // The default for all other platforms
                 let backlog = 128;
diff --git a/library/std/src/sys_common/thread.rs b/library/std/src/sys_common/thread.rs
deleted file mode 100644
index 8f5624bbce9..00000000000
--- a/library/std/src/sys_common/thread.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use crate::env;
-use crate::sync::atomic::{self, Ordering};
-use crate::sys::thread as imp;
-
-pub fn min_stack() -> usize {
-    static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-    match MIN.load(Ordering::Relaxed) {
-        0 => {}
-        n => return n - 1,
-    }
-    let amt = env::var_os("RUST_MIN_STACK").and_then(|s| s.to_str().and_then(|s| s.parse().ok()));
-    let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
-
-    // 0 is our sentinel value, so ensure that we'll never see 0 after
-    // initialization has run
-    MIN.store(amt + 1, Ordering::Relaxed);
-    amt
-}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index fbb882e640b..c1b4440e560 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -53,25 +53,25 @@ use crate::fmt;
 /// # Examples
 ///
 /// ```
-/// use std::cell::RefCell;
+/// use std::cell::Cell;
 /// use std::thread;
 ///
-/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
+/// thread_local!(static FOO: Cell<u32> = Cell::new(1));
 ///
-/// FOO.with_borrow(|v| assert_eq!(*v, 1));
-/// FOO.with_borrow_mut(|v| *v = 2);
+/// assert_eq!(FOO.get(), 1);
+/// FOO.set(2);
 ///
 /// // each thread starts out with the initial value of 1
 /// let t = thread::spawn(move|| {
-///     FOO.with_borrow(|v| assert_eq!(*v, 1));
-///     FOO.with_borrow_mut(|v| *v = 3);
+///     assert_eq!(FOO.get(), 1);
+///     FOO.set(3);
 /// });
 ///
 /// // wait for the thread to complete and bail out on panic
 /// t.join().unwrap();
 ///
 /// // we retain our original value of 2 despite the child thread
-/// FOO.with_borrow(|v| assert_eq!(*v, 2));
+/// assert_eq!(FOO.get(), 2);
 /// ```
 ///
 /// # Platform-specific behavior
@@ -141,15 +141,16 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 /// Publicity and attributes for each static are allowed. Example:
 ///
 /// ```
-/// use std::cell::RefCell;
+/// use std::cell::{Cell, RefCell};
+///
 /// thread_local! {
-///     pub static FOO: RefCell<u32> = RefCell::new(1);
+///     pub static FOO: Cell<u32> = Cell::new(1);
 ///
-///     static BAR: RefCell<f32> = RefCell::new(1.0);
+///     static BAR: RefCell<Vec<f32>> = RefCell::new(vec![1.0, 2.0]);
 /// }
 ///
-/// FOO.with_borrow(|v| assert_eq!(*v, 1));
-/// BAR.with_borrow(|v| assert_eq!(*v, 1.0));
+/// assert_eq!(FOO.get(), 1);
+/// BAR.with_borrow(|v| assert_eq!(v[1], 2.0));
 /// ```
 ///
 /// Note that only shared references (`&T`) to the inner data may be obtained, so a
@@ -164,12 +165,13 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 /// track any additional state.
 ///
 /// ```
-/// use std::cell::Cell;
+/// use std::cell::RefCell;
+///
 /// thread_local! {
-///     pub static FOO: Cell<u32> = const { Cell::new(1) };
+///     pub static FOO: RefCell<Vec<u32>> = const { RefCell::new(Vec::new()) };
 /// }
 ///
-/// assert_eq!(FOO.get(), 1);
+/// FOO.with_borrow(|v| assert_eq!(v.len(), 0));
 /// ```
 ///
 /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
@@ -279,10 +281,9 @@ impl<T: 'static> LocalKey<T> {
     where
         F: FnOnce(&T) -> R,
     {
-        unsafe {
-            let thread_local = (self.inner)(None).ok_or(AccessError)?;
-            Ok(f(thread_local))
-        }
+        // SAFETY: `inner` is safe to call within the lifetime of the thread
+        let thread_local = unsafe { (self.inner)(None).ok_or(AccessError)? };
+        Ok(f(thread_local))
     }
 
     /// Acquires a reference to the value in this TLS key, initializing it with
@@ -301,14 +302,17 @@ impl<T: 'static> LocalKey<T> {
     where
         F: FnOnce(Option<T>, &T) -> R,
     {
-        unsafe {
-            let mut init = Some(init);
-            let reference = (self.inner)(Some(&mut init)).expect(
+        let mut init = Some(init);
+
+        // SAFETY: `inner` is safe to call within the lifetime of the thread
+        let reference = unsafe {
+            (self.inner)(Some(&mut init)).expect(
                 "cannot access a Thread Local Storage value \
                  during or after destruction",
-            );
-            f(init, reference)
-        }
+            )
+        };
+
+        f(init, reference)
     }
 }
 
@@ -377,7 +381,7 @@ impl<T: 'static> LocalKey<Cell<T>> {
     where
         T: Copy,
     {
-        self.with(|cell| cell.get())
+        self.with(Cell::get)
     }
 
     /// Takes the contained value, leaving `Default::default()` in its place.
@@ -407,7 +411,7 @@ impl<T: 'static> LocalKey<Cell<T>> {
     where
         T: Default,
     {
-        self.with(|cell| cell.take())
+        self.with(Cell::take)
     }
 
     /// Replaces the contained value, returning the old value.
@@ -578,7 +582,7 @@ impl<T: 'static> LocalKey<RefCell<T>> {
     where
         T: Default,
     {
-        self.with(|cell| cell.take())
+        self.with(RefCell::take)
     }
 
     /// Replaces the contained value, returning the old value.
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 99ca770aacf..604eb05040b 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -160,6 +160,7 @@ mod tests;
 
 use crate::any::Any;
 use crate::cell::{OnceCell, UnsafeCell};
+use crate::env;
 use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
@@ -171,9 +172,9 @@ use crate::panicking;
 use crate::pin::Pin;
 use crate::ptr::addr_of_mut;
 use crate::str;
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::Arc;
 use crate::sys::thread as imp;
-use crate::sys_common::thread;
 use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::{Duration, Instant};
@@ -468,7 +469,23 @@ impl Builder {
     {
         let Builder { name, stack_size } = self;
 
-        let stack_size = stack_size.unwrap_or_else(thread::min_stack);
+        let stack_size = stack_size.unwrap_or_else(|| {
+            static MIN: AtomicUsize = AtomicUsize::new(0);
+
+            match MIN.load(Ordering::Relaxed) {
+                0 => {}
+                n => return n - 1,
+            }
+
+            let amt = env::var_os("RUST_MIN_STACK")
+                .and_then(|s| s.to_str().and_then(|s| s.parse().ok()))
+                .unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
+
+            // 0 is our sentinel value, so ensure that we'll never see 0 after
+            // initialization has run
+            MIN.store(amt + 1, Ordering::Relaxed);
+            amt
+        });
 
         let my_thread = name.map_or_else(Thread::new_unnamed, |name| unsafe {
             Thread::new(
@@ -1193,17 +1210,17 @@ impl ThreadId {
 
         cfg_if::cfg_if! {
             if #[cfg(target_has_atomic = "64")] {
-                use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
+                use crate::sync::atomic::AtomicU64;
 
                 static COUNTER: AtomicU64 = AtomicU64::new(0);
 
-                let mut last = COUNTER.load(Relaxed);
+                let mut last = COUNTER.load(Ordering::Relaxed);
                 loop {
                     let Some(id) = last.checked_add(1) else {
                         exhausted();
                     };
 
-                    match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
+                    match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) {
                         Ok(_) => return ThreadId(NonZero::new(id).unwrap()),
                         Err(id) => last = id,
                     }
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index 7b11e7c17b1..e2e22e5194f 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -47,10 +47,16 @@ impl ScopeData {
         // chance it overflows to 0, which would result in unsoundness.
         if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
             // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles.
-            self.decrement_num_running_threads(false);
-            panic!("too many running threads in thread scope");
+            self.overflow();
         }
     }
+
+    #[cold]
+    fn overflow(&self) {
+        self.decrement_num_running_threads(false);
+        panic!("too many running threads in thread scope");
+    }
+
     pub(super) fn decrement_num_running_threads(&self, panic: bool) {
         if panic {
             self.a_thread_panicked.store(true, Ordering::Relaxed);
diff --git a/library/stdarch b/library/stdarch
-Subproject 967e7afd87cbea3232581a4a55031134ab88f59
+Subproject 7df81ba8c3e2d02c2ace0c5a6f4f32d800c09e5
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 818a7daadca..768aac912ce 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -152,9 +152,9 @@ v("default-linker", "rust.default-linker", "the default linker")
 # (others are conditionally saved).
 o("manage-submodules", "build.submodules", "let the build manage the git submodules")
 o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)")
-o("bootstrap-cache-path", "build.bootstrap-cache-path", "use provided path for the bootstrap cache")
 o("extended", "build.extended", "build an extended rust tool set")
 
+v("bootstrap-cache-path", None, "use provided path for the bootstrap cache")
 v("tools", None, "List of extended tools will be installed")
 v("codegen-backends", None, "List of codegen backends to build")
 v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
@@ -359,6 +359,8 @@ def apply_args(known_args, option_checking, config):
             set('target.{}.llvm-filecheck'.format(build_triple), value, config)
         elif option.name == 'tools':
             set('build.tools', value.split(','), config)
+        elif option.name == 'bootstrap-cache-path':
+            set('build.bootstrap-cache-path', value, config)
         elif option.name == 'codegen-backends':
             set('rust.codegen-backends', value.split(','), config)
         elif option.name == 'host':
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 55180a82885..37d91b14ca1 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -296,7 +296,7 @@ impl Step for Rustc {
             cargo_subcommand(builder.kind),
         );
 
-        rustc_cargo(builder, &mut cargo, target, compiler.stage);
+        rustc_cargo(builder, &mut cargo, target, &compiler);
 
         // For ./x.py clippy, don't run with --all-targets because
         // linting tests and benchmarks can produce very noisy results
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index e03997181ee..9420e40d6c2 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -945,55 +945,10 @@ impl Step for Rustc {
             "build",
         );
 
-        rustc_cargo(builder, &mut cargo, target, compiler.stage);
+        rustc_cargo(builder, &mut cargo, target, &compiler);
 
-        if builder.config.rust_profile_use.is_some()
-            && builder.config.rust_profile_generate.is_some()
-        {
-            panic!("Cannot use and generate PGO profiles at the same time");
-        }
-
-        // With LLD, we can use ICF (identical code folding) to reduce the executable size
-        // of librustc_driver/rustc and to improve i-cache utilization.
-        //
-        // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF)
-        // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
-        // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
-        // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
-        if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() {
-            cargo.rustflag("-Clink-args=-Wl,--icf=all");
-        }
-
-        let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
-            if compiler.stage == 1 {
-                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");
-                true
-            } else {
-                false
-            }
-        } else if let Some(path) = &builder.config.rust_profile_use {
-            if compiler.stage == 1 {
-                cargo.rustflag(&format!("-Cprofile-use={path}"));
-                if builder.is_verbose() {
-                    cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
-                }
-                true
-            } else {
-                false
-            }
-        } else {
-            false
-        };
-        if is_collecting {
-            // Ensure paths to Rust sources are relative, not absolute.
-            cargo.rustflag(&format!(
-                "-Cllvm-args=-static-func-strip-dirname-prefix={}",
-                builder.config.src.components().count()
-            ));
-        }
+        // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be
+        // consistently applied by check/doc/test modes too.
 
         for krate in &*self.crates {
             cargo.arg("-p").arg(krate);
@@ -1044,7 +999,12 @@ impl Step for Rustc {
     }
 }
 
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) {
+pub fn rustc_cargo(
+    builder: &Builder<'_>,
+    cargo: &mut Cargo,
+    target: TargetSelection,
+    compiler: &Compiler,
+) {
     cargo
         .arg("--features")
         .arg(builder.rustc_features(builder.kind, target))
@@ -1055,7 +1015,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec
 
     // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
     // and may just be a time sink.
-    if stage != 0 {
+    if compiler.stage != 0 {
         match builder.config.rust_lto {
             RustcLto::Thin | RustcLto::Fat => {
                 // Since using LTO for optimizing dylibs is currently experimental,
@@ -1081,7 +1041,52 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec
         cargo.rustflag("-Clto=off");
     }
 
-    rustc_cargo_env(builder, cargo, target, stage);
+    // With LLD, we can use ICF (identical code folding) to reduce the executable size
+    // of librustc_driver/rustc and to improve i-cache utilization.
+    //
+    // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF)
+    // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
+    // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
+    // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
+    if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() {
+        cargo.rustflag("-Clink-args=-Wl,--icf=all");
+    }
+
+    if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() {
+        panic!("Cannot use and generate PGO profiles at the same time");
+    }
+    let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
+        if compiler.stage == 1 {
+            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");
+            true
+        } else {
+            false
+        }
+    } else if let Some(path) = &builder.config.rust_profile_use {
+        if compiler.stage == 1 {
+            cargo.rustflag(&format!("-Cprofile-use={path}"));
+            if builder.is_verbose() {
+                cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
+            }
+            true
+        } else {
+            false
+        }
+    } else {
+        false
+    };
+    if is_collecting {
+        // Ensure paths to Rust sources are relative, not absolute.
+        cargo.rustflag(&format!(
+            "-Cllvm-args=-static-func-strip-dirname-prefix={}",
+            builder.config.src.components().count()
+        ));
+    }
+
+    rustc_cargo_env(builder, cargo, target, compiler.stage);
 }
 
 pub fn rustc_cargo_env(
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 51b5cdc0565..a22cbeacf01 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -804,7 +804,7 @@ impl Step for Rustc {
         // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
         // cargo.rustdocflag("--generate-link-to-definition");
 
-        compile::rustc_cargo(builder, &mut cargo, target, compiler.stage);
+        compile::rustc_cargo(builder, &mut cargo, target, &compiler);
         cargo.arg("-Zunstable-options");
         cargo.arg("-Zskip-rustdoc-fingerprint");
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 1e68f8d276a..09763e6bf01 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2713,7 +2713,7 @@ impl Step for Crate {
                 }
             }
             Mode::Rustc => {
-                compile::rustc_cargo(builder, &mut cargo, target, compiler.stage);
+                compile::rustc_cargo(builder, &mut cargo, target, &compiler);
             }
             _ => panic!("can only test libraries"),
         };
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 96dec975250..c84eb8a684f 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -2483,9 +2483,20 @@ impl Config {
                 llvm::is_ci_llvm_available(self, asserts)
             }
         };
+
         match download_ci_llvm {
-            None => self.channel == "dev" && if_unchanged(),
-            Some(StringOrBool::Bool(b)) => b,
+            None => {
+                (self.channel == "dev" || self.download_rustc_commit.is_some()) && if_unchanged()
+            }
+            Some(StringOrBool::Bool(b)) => {
+                if !b && self.download_rustc_commit.is_some() {
+                    panic!(
+                        "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`."
+                    );
+                }
+
+                b
+            }
             // FIXME: "if-available" is deprecated. Remove this block later (around mid 2024)
             // to not break builds between the recent-to-old checkouts.
             Some(StringOrBool::String(s)) if s == "if-available" => {
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 09fbbac466c..5c459e5cd18 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -99,6 +99,7 @@ ENV TARGETS=$TARGETS,thumbv8m.base-none-eabi
 ENV TARGETS=$TARGETS,thumbv8m.main-none-eabi
 ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf
 ENV TARGETS=$TARGETS,riscv32i-unknown-none-elf
+ENV TARGETS=$TARGETS,riscv32im-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf
@@ -130,6 +131,8 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft
     CFLAGS_aarch64_unknown_none=-mstrict-align -march=armv8-a+fp+simd \
     CC_riscv32i_unknown_none_elf=riscv32-unknown-elf-gcc \
     CFLAGS_riscv32i_unknown_none_elf=-march=rv32i -mabi=ilp32 \
+    CC_riscv32im_unknown_none_elf=riscv32-unknown-elf-gcc \
+    CFLAGS_riscv32im_unknown_none_elf=-march=rv32im -mabi=ilp32 \
     CC_riscv32imc_unknown_none_elf=riscv32-unknown-elf-gcc \
     CFLAGS_riscv32imc_unknown_none_elf=-march=rv32imc -mabi=ilp32 \
     CC_riscv32imac_unknown_none_elf=riscv32-unknown-elf-gcc \
diff --git a/src/doc/unstable-book/src/compiler-flags/linker-features.md b/src/doc/unstable-book/src/compiler-flags/linker-features.md
new file mode 100644
index 00000000000..643fcf7c6d7
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/linker-features.md
@@ -0,0 +1,35 @@
+# `linker-features`
+
+--------------------
+
+The `-Zlinker-features` compiler flag allows enabling or disabling specific features used during
+linking, and is intended to be stabilized under the codegen options as `-Clinker-features`.
+
+These feature flags are a flexible extension mechanism that is complementary to linker flavors,
+designed to avoid the combinatorial explosion of having to create a new set of flavors for each
+linker feature we'd want to use.
+
+For example, this design allows:
+- default feature sets for principal flavors, or for specific targets.
+- flavor-specific features: for example, clang offers automatic cross-linking with `--target`, which
+  gcc-style compilers don't support. The *flavor* is still a C/C++ compiler, and we don't want to
+  multiply the number of flavors for this use-case. Instead, we can have a single `+target` feature.
+- umbrella features: for example, if clang accumulates more features in the future than just the
+  `+target` above. That could be modeled as `+clang`.
+- niche features for resolving specific issues: for example, on Apple targets the linker flag
+  implementing the `as-needed` native link modifier (#99424) is only possible on sufficiently recent
+  linker versions.
+- still allows for discovery and automation, for example via feature detection. This can be useful
+  in exotic environments/build systems.
+
+The flag accepts a comma-separated list of features, individually enabled (`+features`) or disabled
+(`-features`), though currently only one is exposed on the CLI:
+- `lld`: to toggle using the lld linker, either the system-installed binary, or the self-contained
+  `rust-lld` linker.
+
+As described above, this list is intended to grow in the future.
+
+One of the most common uses of this flag will be to toggle self-contained linking with `rust-lld` on
+and off: `-Clinker-features=+lld -Clink-self-contained=+linker` will use the toolchain's `rust-lld`
+as the linker. Inversely, `-Clinker-features=-lld` would opt out of that, if the current target had
+self-contained linking enabled by default.
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 59acbc73db4..43e11b6d57d 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - M68k
 - CSKY
 - s390x
+- Arm64EC
 
 ## Register classes
 
@@ -51,6 +52,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
 | s390x        | `freg`         | `f[0-15]`                          | `f`                  |
+| Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
+| Arm64EC      | `vreg`         | `v[0-15]`                          | `w`                  |
+| Arm64EC      | `vreg_low16`   | `v[0-15]`                          | `x`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -86,6 +90,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | s390x        | `reg`, `reg_addr`               | None           | `i8`, `i16`, `i32`, `i64`               |
 | s390x        | `freg`                          | None           | `f32`, `f64`                            |
+| Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
+| Arm64EC      | `vreg`                          | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 
 ## Register aliases
 
@@ -118,6 +124,12 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r29`         | `rtb`     |
 | CSKY         | `r30`         | `svbr`    |
 | CSKY         | `r31`         | `tls`     |
+| Arm64EC      | `x[0-30]`     | `w[0-30]` |
+| Arm64EC      | `x29`         | `fp`      |
+| Arm64EC      | `x30`         | `lr`      |
+| Arm64EC      | `sp`          | `wsp`     |
+| Arm64EC      | `xzr`         | `wzr`     |
+| Arm64EC      | `v[0-15]`     | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` |
 
 > **Notes**:
 > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
@@ -128,8 +140,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | All          | `sp`, `r15` (s390x)                     | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output.                                                                                                                             |
-| All          | `r19` (Hexagon)                         | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
+| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output.                                                                                                                             |
+| All          | `r19` (Hexagon), `x19` (Arm64EC)        | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
 | MIPS         | `$26`/`$k0`, `$27`/`$k1`                | OS-reserved registers.                                                                                                                                                              |
@@ -145,6 +157,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r15`                                   | This is the link register. |
 | CSKY         | `r[26-30]`                              | Reserved by its ABI.       |
 | CSKY         | `r31`                                   | This is the TLS register.  |
+| Arm64EC      | `xzr`                                   | This is a constant zero register which can't be modified. |
+| Arm64EC      | `x18`                                   | This is an OS-reserved register. |
+| Arm64EC      | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. |
 
 
 ## Template modifiers
@@ -165,6 +180,16 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | s390x        | `freg`         | None     | `%f0`          | None          |
 | CSKY         | `reg`          | None     | `r0`           | None          |
 | CSKY         | `freg`         | None     | `f0`           | None          |
+| Arm64EC      | `reg`          | None     | `x0`           | `x`           |
+| Arm64EC      | `reg`          | `w`      | `w0`           | `w`           |
+| Arm64EC      | `reg`          | `x`      | `x0`           | `x`           |
+| Arm64EC      | `vreg`         | None     | `v0`           | None          |
+| Arm64EC      | `vreg`         | `v`      | `v0`           | None          |
+| Arm64EC      | `vreg`         | `b`      | `b0`           | `b`           |
+| Arm64EC      | `vreg`         | `h`      | `h0`           | `h`           |
+| Arm64EC      | `vreg`         | `s`      | `s0`           | `s`           |
+| Arm64EC      | `vreg`         | `d`      | `d0`           | `d`           |
+| Arm64EC      | `vreg`         | `q`      | `q0`           | `q`           |
 
 # Flags covered by `preserves_flags`
 
@@ -177,3 +202,6 @@ These flags registers must be restored upon exiting the asm block if the `preser
   - The condition code register `ccr`.
 - s390x
   - The condition code register `cc`.
+- Arm64EC
+  - Condition flags (`NZCV` register).
+  - Floating-point status (`FPSR` register).
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6f86c6450d9..4d506edc47b 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -63,8 +63,6 @@ pub(crate) fn try_inline(
 
     let import_def_id = attrs.and_then(|(_, def_id)| def_id);
 
-    let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
-
     let kind = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, ItemType::Trait);
@@ -134,7 +132,11 @@ pub(crate) fn try_inline(
             cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did)))
         }
         Res::Def(DefKind::Macro(kind), did) => {
-            let mac = build_macro(cx, did, name, import_def_id, kind, attrs.is_doc_hidden());
+            let is_doc_hidden = cx.tcx.is_doc_hidden(did)
+                || attrs_without_docs
+                    .map(|(attrs, _)| attrs)
+                    .is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden));
+            let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden);
 
             let type_kind = match kind {
                 MacroKind::Bang => ItemType::Macro,
@@ -148,8 +150,14 @@ pub(crate) fn try_inline(
     };
 
     cx.inlined.insert(did.into());
-    let mut item =
-        clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg);
+    let mut item = crate::clean::generate_item_with_correct_attrs(
+        cx,
+        kind,
+        did,
+        name,
+        import_def_id.and_then(|def_id| def_id.as_local()),
+        None,
+    );
     // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
     item.inline_stmt_id = import_def_id;
     ret.push(item);
@@ -179,6 +187,7 @@ pub(crate) fn try_inline_glob(
                 .iter()
                 .filter(|child| !child.reexport_chain.is_empty())
                 .filter_map(|child| child.res.opt_def_id())
+                .filter(|def_id| !cx.tcx.is_doc_hidden(def_id))
                 .collect();
             let attrs = cx.tcx.hir().attrs(import.hir_id());
             let mut items = build_module_items(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 12f45fe4979..925d41e67f8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3007,22 +3007,22 @@ fn clean_use_statement_inner<'tcx>(
             // were specifically asked for it
             denied = true;
         }
-        if !denied {
-            if let Some(mut items) = inline::try_inline(
+        if !denied
+            && let Some(mut items) = inline::try_inline(
                 cx,
                 path.res,
                 name,
                 Some((attrs, Some(import_def_id))),
                 &mut Default::default(),
-            ) {
-                items.push(Item::from_def_id_and_parts(
-                    import_def_id,
-                    None,
-                    ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
-                    cx,
-                ));
-                return items;
-            }
+            )
+        {
+            items.push(Item::from_def_id_and_parts(
+                import_def_id,
+                None,
+                ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
+                cx,
+            ));
+            return items;
         }
         Import::new_simple(name, resolve_use_source(cx, path), true)
     };
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index dc62fbb5edb..aa923cc6117 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -580,7 +580,14 @@ pub(crate) fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Opti
 /// This function exists because it runs on `hir::Attributes` whereas the other is a
 /// `clean::Attributes` method.
 pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
-    tcx.get_attrs(did, sym::doc)
+    attrs_have_doc_flag(tcx.get_attrs(did, sym::doc), flag)
+}
+
+pub(crate) fn attrs_have_doc_flag<'a>(
+    mut attrs: impl Iterator<Item = &'a ast::Attribute>,
+    flag: Symbol,
+) -> bool {
+    attrs
         .any(|attr| attr.meta_item_list().is_some_and(|l| rustc_attr::list_contains_name(&l, flag)))
 }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 9802097ea29..11fc99eb511 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -203,10 +203,10 @@ impl Cache {
 impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if item.item_id.is_local() {
-            let is_stripped = matches!(*item.kind, clean::ItemKind::StrippedItem(..));
             debug!(
-                "folding {} (stripped: {is_stripped:?}) \"{:?}\", id {:?}",
+                "folding {} (stripped: {:?}) \"{:?}\", id {:?}",
                 item.type_(),
+                item.is_stripped(),
                 item.name,
                 item.item_id
             );
@@ -246,13 +246,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
             self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| (**t).clone());
-        }
-
-        // Collect all the implementors of traits.
-        if let clean::ImplItem(ref i) = *item.kind
+        } else if let clean::ImplItem(ref i) = *item.kind
             && let Some(trait_) = &i.trait_
             && !i.kind.is_blanket()
         {
+            // Collect all the implementors of traits.
             self.cache
                 .implementors
                 .entry(trait_.def_id())
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 0941f758de5..1dc9041658e 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -7,8 +7,7 @@
     <meta name="description" content="{{page.description}}"> {# #}
     <title>{{page.title}}</title> {# #}
     <script>if(window.location.protocol!=="file:") {# Hack to skip preloading fonts locally - see #98769 #}
-    for(f of "{{files.source_serif_4_regular}},{{files.fira_sans_regular}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",")) {# #}
-     document.write(`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`) {# #}
+    document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_regular}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #}
     </script> {# #}
     <link rel="stylesheet" {#+ #}
           href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 28e7b2bc0a812f90126be30f48a00a4ada990ea
+Subproject 48eca1b164695022295ce466b64b44e4e0228b0
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 0599afca09f..790bed580fd 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for LargeIncludeFile {
             span_lint_and_note(
                 cx,
                 LARGE_INCLUDE_FILE,
-                expr.span,
+                expr.span.source_callsite(),
                 "attempted to include a large file",
                 None,
                 format!(
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index b3c729dacdd..3aa979cb11b 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -300,7 +300,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                     e.span,
                     "calling `as_bytes()` on `include_str!(..)`",
                     "consider using `include_bytes!(..)` instead",
-                    snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
+                    snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen(
                         "include_str",
                         "include_bytes",
                         1,
diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
index b45cb11939f..34224065f07 100644
--- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
+++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
@@ -7,7 +7,6 @@ LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
    = note: the configuration allows a maximum size of 600 bytes
    = note: `-D clippy::large-include-file` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]`
-   = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: attempted to include a large file
   --> tests/ui-toml/large_include_file/large_include_file.rs:14:35
@@ -16,7 +15,6 @@ LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt");
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the configuration allows a maximum size of 600 bytes
-   = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_docs.stderr b/src/tools/clippy/tests/ui/empty_docs.stderr
index 28ebea22c5d..5fd7272d7c1 100644
--- a/src/tools/clippy/tests/ui/empty_docs.stderr
+++ b/src/tools/clippy/tests/ui/empty_docs.stderr
@@ -25,19 +25,20 @@ LL |         ///
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:30:5
+  --> tests/ui/empty_docs.rs:30:13
    |
 LL |     #[doc = ""]
-   |     ^^^^^^^^^^^
+   |             ^^
    |
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:33:5
+  --> tests/ui/empty_docs.rs:33:13
    |
-LL | /     #[doc = ""]
+LL |       #[doc = ""]
+   |  _____________^
 LL | |     #[doc = ""]
-   | |_______________^
+   | |______________^
    |
    = help: consider removing or filling it
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index ec944cb7fb4..e6f4accfd7b 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -790,15 +790,18 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-thumb",
     "ignore-thumbv8m.base-none-eabi",
     "ignore-thumbv8m.main-none-eabi",
+    "ignore-tvos",
     "ignore-unix",
     "ignore-unknown",
     "ignore-uwp",
+    "ignore-visionos",
     "ignore-vxworks",
     "ignore-wasi",
     "ignore-wasm",
     "ignore-wasm32",
     "ignore-wasm32-bare",
     "ignore-wasm64",
+    "ignore-watchos",
     "ignore-windows",
     "ignore-windows-gnu",
     "ignore-x32",
@@ -856,6 +859,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-cdb",
     "only-gnu",
     "only-i686-pc-windows-msvc",
+    "only-ios",
     "only-linux",
     "only-loongarch64",
     "only-loongarch64-unknown-linux-gnu",
@@ -871,10 +875,13 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-sparc64",
     "only-stable",
     "only-thumb",
+    "only-tvos",
     "only-unix",
+    "only-visionos",
     "only-wasm32",
     "only-wasm32-bare",
     "only-wasm32-wasip1",
+    "only-watchos",
     "only-windows",
     "only-x86",
     "only-x86_64",
@@ -935,16 +942,25 @@ struct HeaderLine<'ln> {
 pub(crate) struct CheckDirectiveResult<'ln> {
     is_known_directive: bool,
     directive_name: &'ln str,
+    trailing_directive: Option<&'ln str>,
 }
 
-// Returns `(is_known_directive, directive_name)`.
 pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
-    let directive_name =
-        directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln);
+    let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
+
+    let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
+    let trailing_directive = {
+        // 1. is the directive name followed by a space? (to exclude `:`)
+        matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" "))
+            // 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
+            && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
+    }
+    .then_some(trailing);
 
     CheckDirectiveResult {
         is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
         directive_name: directive_ln,
+        trailing_directive,
     }
 }
 
@@ -1014,7 +1030,8 @@ fn iter_header(
             if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
                 let directive_ln = non_revisioned_directive_line.trim();
 
-                let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln);
+                let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
+                    check_directive(directive_ln);
 
                 if !is_known_directive {
                     *poisoned = true;
@@ -1028,6 +1045,21 @@ fn iter_header(
 
                     return;
                 }
+
+                if let Some(trailing_directive) = &trailing_directive {
+                    *poisoned = true;
+
+                    eprintln!(
+                        "error: detected trailing compiletest test directive `{}` in {}:{}\n \
+                          help: put the trailing directive in it's own line: `//@ {}`",
+                        trailing_directive,
+                        testfile.display(),
+                        line_number,
+                        trailing_directive,
+                    );
+
+                    return;
+                }
             }
 
             it(HeaderLine {
@@ -1051,7 +1083,8 @@ fn iter_header(
 
             let rest = rest.trim_start();
 
-            let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest);
+            let CheckDirectiveResult { is_known_directive, directive_name, .. } =
+                check_directive(rest);
 
             if is_known_directive {
                 *poisoned = true;
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 83f0755b5c8..8a37a4d6d31 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -667,3 +667,24 @@ fn test_non_rs_unknown_directive_not_checked() {
     );
     assert!(!poisoned);
 }
+
+#[test]
+fn test_trailing_directive() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm");
+    assert!(poisoned);
+}
+
+#[test]
+fn test_trailing_directive_with_comment() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86   only-arm with comment");
+    assert!(poisoned);
+}
+
+#[test]
+fn test_not_trailing_directive() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental");
+    assert!(!poisoned);
+}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 327e34ea36b..5212f1430d8 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3785,6 +3785,14 @@ impl<'test> TestCx<'test> {
         debug!(?support_lib_deps);
         debug!(?support_lib_deps_deps);
 
+        let orig_dylib_env_paths =
+            Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap()));
+
+        let mut host_dylib_env_paths = Vec::new();
+        host_dylib_env_paths.push(cwd.join(&self.config.compile_lib_path));
+        host_dylib_env_paths.extend(orig_dylib_env_paths.iter().cloned());
+        let host_dylib_env_paths = env::join_paths(host_dylib_env_paths).unwrap();
+
         let mut cmd = Command::new(&self.config.rustc_path);
         cmd.arg("-o")
             .arg(&recipe_bin)
@@ -3801,6 +3809,7 @@ impl<'test> TestCx<'test> {
             .env("RUSTC", cwd.join(&self.config.rustc_path))
             .env("TMPDIR", &tmpdir)
             .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
+            .env(dylib_env_var(), &host_dylib_env_paths)
             .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
             .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
             .env("LLVM_COMPONENTS", &self.config.llvm_components)
@@ -3828,19 +3837,15 @@ impl<'test> TestCx<'test> {
         // Finally, we need to run the recipe binary to build and run the actual tests.
         debug!(?recipe_bin);
 
-        let mut dylib_env_paths = String::new();
-        dylib_env_paths.push_str(&env::var(dylib_env_var()).unwrap());
-        dylib_env_paths.push(':');
-        dylib_env_paths.push_str(&support_lib_path.parent().unwrap().to_string_lossy());
-        dylib_env_paths.push(':');
-        dylib_env_paths.push_str(
-            &stage_std_path.join("rustlib").join(&self.config.host).join("lib").to_string_lossy(),
-        );
+        let mut dylib_env_paths = orig_dylib_env_paths.clone();
+        dylib_env_paths.push(support_lib_path.parent().unwrap().to_path_buf());
+        dylib_env_paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib"));
+        let dylib_env_paths = env::join_paths(dylib_env_paths).unwrap();
 
-        let mut target_rpath_env_path = String::new();
-        target_rpath_env_path.push_str(&tmpdir.to_string_lossy());
-        target_rpath_env_path.push(':');
-        target_rpath_env_path.push_str(&dylib_env_paths);
+        let mut target_rpath_env_path = Vec::new();
+        target_rpath_env_path.push(&tmpdir);
+        target_rpath_env_path.extend(&orig_dylib_env_paths);
+        let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap();
 
         let mut cmd = Command::new(&recipe_bin);
         cmd.current_dir(&self.testpaths.file)
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 3f6c484a057..04f3b2918b5 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -454,15 +454,10 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
                 continue;
             }
             // If the REPLACE_LIBRS hack is enabled and we are building a `lib.rs` file, and a
-            // `lib.miri.rs` file exists, then build that instead. We only consider relative paths
-            // as cargo uses those for files in the workspace; dependencies from crates.io get
-            // absolute paths.
+            // `lib.miri.rs` file exists, then build that instead.
             if replace_librs {
                 let path = Path::new(&arg);
-                if path.is_relative()
-                    && path.file_name().is_some_and(|f| f == "lib.rs")
-                    && path.is_file()
-                {
+                if path.file_name().is_some_and(|f| f == "lib.rs") && path.is_file() {
                     let miri_rs = Path::new(&arg).with_extension("miri.rs");
                     if miri_rs.is_file() {
                         if verbose > 0 {
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 7b7921219e6..2a663d300a7 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -468,6 +468,86 @@ fn unary_op_ps<'tcx>(
     Ok(())
 }
 
+enum ShiftOp {
+    /// Shift left, logically (shift in zeros) -- same as shift left, arithmetically
+    Left,
+    /// Shift right, logically (shift in zeros)
+    RightLogic,
+    /// Shift right, arithmetically (shift in sign)
+    RightArith,
+}
+
+/// Shifts each element of `left` by a scalar amount. The shift amount
+/// is determined by the lowest 64 bits of `right` (which is a 128-bit vector).
+///
+/// For logic shifts, when right is larger than BITS - 1, zero is produced.
+/// For arithmetic right-shifts, when right is larger than BITS - 1, the sign
+/// bit is copied to remaining bits.
+fn shift_simd_by_scalar<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    which: ShiftOp,
+    dest: &MPlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (dest, dest_len) = this.mplace_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    // `right` may have a different length, and we only care about its
+    // lowest 64bit anyway.
+
+    // Get the 64-bit shift operand and convert it to the type expected
+    // by checked_{shl,shr} (u32).
+    // It is ok to saturate the value to u32::MAX because any value
+    // above BITS - 1 will produce the same result.
+    let shift = u32::try_from(extract_first_u64(this, right)?).unwrap_or(u32::MAX);
+
+    for i in 0..dest_len {
+        let left = this.read_scalar(&this.project_index(&left, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = match which {
+            ShiftOp::Left => {
+                let left = left.to_uint(dest.layout.size)?;
+                let res = left.checked_shl(shift).unwrap_or(0);
+                // `truncate` is needed as left-shift can make the absolute value larger.
+                Scalar::from_uint(dest.layout.size.truncate(res), dest.layout.size)
+            }
+            ShiftOp::RightLogic => {
+                let left = left.to_uint(dest.layout.size)?;
+                let res = left.checked_shr(shift).unwrap_or(0);
+                // No `truncate` needed as right-shift can only make the absolute value smaller.
+                Scalar::from_uint(res, dest.layout.size)
+            }
+            ShiftOp::RightArith => {
+                let left = left.to_int(dest.layout.size)?;
+                // On overflow, copy the sign bit to the remaining bits
+                let res = left.checked_shr(shift).unwrap_or(left >> 127);
+                // No `truncate` needed as right-shift can only make the absolute value smaller.
+                Scalar::from_int(res, dest.layout.size)
+            }
+        };
+        this.write_scalar(res, &dest)?;
+    }
+
+    Ok(())
+}
+
+/// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts
+/// the first value.
+fn extract_first_u64<'tcx>(
+    this: &crate::MiriInterpCx<'_, 'tcx>,
+    op: &OpTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, u64> {
+    // Transmute vector to `[u64; 2]`
+    let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?;
+    let op = op.transmute(array_layout, this)?;
+
+    // Get the first u64 from the array
+    this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()
+}
+
 // Rounds the first element of `right` according to `rounding`
 // and copies the remaining elements from `left`.
 fn round_first<'tcx, F: rustc_apfloat::Float>(
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index eb2cc9d37c8..9db30d7ddca 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -1,10 +1,11 @@
 use rustc_apfloat::ieee::Double;
-use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
-use super::{bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, FloatBinOp};
+use super::{
+    bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, shift_simd_by_scalar,
+    FloatBinOp, ShiftOp,
+};
 use crate::*;
 use shims::foreign_items::EmulateForeignItemResult;
 
@@ -109,156 +110,27 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.write_scalar(Scalar::from_u64(res.into()), &dest)?;
                 }
             }
-            // Used to implement the _mm_{sll,srl,sra}_epi16 functions.
-            // Shifts 16-bit packed integers in left by the amount in right.
-            // Both operands are vectors of 16-bit integers. However, right is
-            // interpreted as a single 64-bit integer (remaining bits are ignored).
-            // For logic shifts, when right is larger than 15, zero is produced.
-            // For arithmetic shifts, when right is larger than 15, the sign bit
+            // Used to implement the _mm_{sll,srl,sra}_epi{16,32,64} functions
+            // (except _mm_sra_epi64, which is not available in SSE2).
+            // Shifts N-bit packed integers in left by the amount in right.
+            // Both operands are 128-bit vectors. However, right is interpreted as
+            // a single 64-bit integer (remaining bits are ignored).
+            // For logic shifts, when right is larger than N - 1, zero is produced.
+            // For arithmetic shifts, when right is larger than N - 1, the sign bit
             // is copied to remaining bits.
-            "psll.w" | "psrl.w" | "psra.w" => {
+            "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
+            | "psrl.q" => {
                 let [left, right] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.mplace_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
-
-                enum ShiftOp {
-                    Sll,
-                    Srl,
-                    Sra,
-                }
                 let which = match unprefixed_name {
-                    "psll.w" => ShiftOp::Sll,
-                    "psrl.w" => ShiftOp::Srl,
-                    "psra.w" => ShiftOp::Sra,
+                    "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
+                    "psrl.w" | "psrl.d" | "psrl.q" => ShiftOp::RightLogic,
+                    "psra.w" | "psra.d" => ShiftOp::RightArith,
                     _ => unreachable!(),
                 };
 
-                // Get the 64-bit shift operand and convert it to the type expected
-                // by checked_{shl,shr} (u32).
-                // It is ok to saturate the value to u32::MAX because any value
-                // above 15 will produce the same result.
-                let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX);
-
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    let res = match which {
-                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
-                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
-                        #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
-                        ShiftOp::Sra => {
-                            // Convert u16 to i16 to use arithmetic shift
-                            let left = left as i16;
-                            // Copy the sign bit to the remaining bits
-                            left.checked_shr(shift).unwrap_or(left >> 15) as u16
-                        }
-                    };
-
-                    this.write_scalar(Scalar::from_u16(res), &dest)?;
-                }
-            }
-            // Used to implement the _mm_{sll,srl,sra}_epi32 functions.
-            // 32-bit equivalent to the shift functions above.
-            "psll.d" | "psrl.d" | "psra.d" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.mplace_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
-
-                enum ShiftOp {
-                    Sll,
-                    Srl,
-                    Sra,
-                }
-                let which = match unprefixed_name {
-                    "psll.d" => ShiftOp::Sll,
-                    "psrl.d" => ShiftOp::Srl,
-                    "psra.d" => ShiftOp::Sra,
-                    _ => unreachable!(),
-                };
-
-                // Get the 64-bit shift operand and convert it to the type expected
-                // by checked_{shl,shr} (u32).
-                // It is ok to saturate the value to u32::MAX because any value
-                // above 31 will produce the same result.
-                let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX);
-
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u32()?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    let res = match which {
-                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
-                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
-                        #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
-                        ShiftOp::Sra => {
-                            // Convert u32 to i32 to use arithmetic shift
-                            let left = left as i32;
-                            // Copy the sign bit to the remaining bits
-                            left.checked_shr(shift).unwrap_or(left >> 31) as u32
-                        }
-                    };
-
-                    this.write_scalar(Scalar::from_u32(res), &dest)?;
-                }
-            }
-            // Used to implement the _mm_{sll,srl}_epi64 functions.
-            // 64-bit equivalent to the shift functions above, except _mm_sra_epi64,
-            // which is not available in SSE2.
-            "psll.q" | "psrl.q" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.mplace_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
-
-                enum ShiftOp {
-                    Sll,
-                    Srl,
-                }
-                let which = match unprefixed_name {
-                    "psll.q" => ShiftOp::Sll,
-                    "psrl.q" => ShiftOp::Srl,
-                    _ => unreachable!(),
-                };
-
-                // Get the 64-bit shift operand and convert it to the type expected
-                // by checked_{shl,shr} (u32).
-                // It is ok to saturate the value to u32::MAX because any value
-                // above 63 will produce the same result.
-                let shift = this
-                    .read_scalar(&this.project_index(&right, 0)?)?
-                    .to_u64()?
-                    .try_into()
-                    .unwrap_or(u32::MAX);
-
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u64()?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    let res = match which {
-                        ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0),
-                        ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0),
-                    };
-
-                    this.write_scalar(Scalar::from_u64(res), &dest)?;
-                }
+                shift_simd_by_scalar(this, left, right, which, dest)?;
             }
             // Used to implement the _mm_cvtps_epi32, _mm_cvttps_epi32, _mm_cvtpd_epi32
             // and _mm_cvttpd_epi32 functions.
@@ -585,17 +457,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         Ok(EmulateForeignItemResult::NeedsJumping)
     }
 }
-
-/// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts
-/// the first value.
-fn extract_first_u64<'tcx>(
-    this: &crate::MiriInterpCx<'_, 'tcx>,
-    op: &MPlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, u64> {
-    // Transmute vector to `[u64; 2]`
-    let u64_array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?;
-    let op = op.transmute(u64_array_layout, this)?;
-
-    // Get the first u64 from the array
-    this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()
-}
diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs
index 2c9ad4f1700..a2d51902652 100644
--- a/src/tools/run-make-support/src/cc.rs
+++ b/src/tools/run-make-support/src/cc.rs
@@ -1,6 +1,6 @@
 use std::env;
 use std::path::Path;
-use std::process::{Command, Output};
+use std::process::Command;
 
 use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname};
 
@@ -19,6 +19,8 @@ pub struct Cc {
     cmd: Command,
 }
 
+crate::impl_common_helpers!(Cc);
+
 impl Cc {
     /// Construct a new platform-specific C compiler invocation.
     ///
@@ -43,22 +45,6 @@ impl Cc {
         self
     }
 
-    /// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various
-    /// possible C compilers on the various platforms to check which arguments are legal for
-    /// which compiler.
-    pub fn arg(&mut self, flag: &str) -> &mut Self {
-        self.cmd.arg(flag);
-        self
-    }
-
-    /// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the
-    /// various possible C compilers on the various platforms to check which arguments are legal
-    /// for which compiler.
-    pub fn args(&mut self, args: &[&str]) -> &mut Self {
-        self.cmd.args(args);
-        self
-    }
-
     /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
     /// is under `$TMPDIR`.
     pub fn out_exe(&mut self, name: &str) -> &mut Self {
@@ -85,25 +71,6 @@ impl Cc {
 
         self
     }
-
-    /// Run the constructed C invocation command and assert that it is successfully run.
-    #[track_caller]
-    pub fn run(&mut self) -> Output {
-        let caller_location = std::panic::Location::caller();
-        let caller_line_number = caller_location.line();
-
-        let output = self.cmd.output().unwrap();
-        if !output.status.success() {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
-        }
-        output
-    }
-
-    /// Inspect what the underlying [`Command`] is up to the current construction.
-    pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
-        f(&self.cmd);
-        self
-    }
 }
 
 /// `EXTRACFLAGS`
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index e70acf58571..47b46a0a699 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -1,3 +1,8 @@
+//! `run-make-support` is a support library for run-make tests. It provides command wrappers and
+//! convenience utility functions to help test writers reduce duplication. The support library
+//! notably is built via cargo: this means that if your test wants some non-trivial utility, such
+//! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
+
 pub mod cc;
 pub mod run;
 pub mod rustc;
@@ -82,7 +87,7 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
     cygpath.arg(path.as_ref());
     let output = cygpath.output().unwrap();
     if !output.status.success() {
-        handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number);
+        handle_failed_output(&cygpath, output, caller_line_number);
     }
     let s = String::from_utf8(output.stdout).unwrap();
     // cygpath -w can attach a newline
@@ -98,20 +103,158 @@ pub fn uname() -> String {
     let mut uname = Command::new("uname");
     let output = uname.output().unwrap();
     if !output.status.success() {
-        handle_failed_output(&format!("{:#?}", uname), output, caller_line_number);
+        handle_failed_output(&uname, output, caller_line_number);
     }
     String::from_utf8(output.stdout).unwrap()
 }
 
-fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
+fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32) -> ! {
     if output.status.success() {
-        eprintln!("command incorrectly succeeded at line {caller_line_number}");
+        eprintln!("command unexpectedly succeeded at line {caller_line_number}");
     } else {
         eprintln!("command failed at line {caller_line_number}");
     }
-    eprintln!("{cmd}");
+    eprintln!("{cmd:?}");
     eprintln!("output status: `{}`", output.status);
     eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
     eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap());
     std::process::exit(1)
 }
+
+/// Set the runtime library path as needed for running the host rustc/rustdoc/etc.
+pub fn set_host_rpath(cmd: &mut Command) {
+    let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
+    cmd.env(&ld_lib_path_envvar, {
+        let mut paths = vec![];
+        paths.push(PathBuf::from(env::var("TMPDIR").unwrap()));
+        paths.push(PathBuf::from(env::var("HOST_RPATH_DIR").unwrap()));
+        for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) {
+            paths.push(p.to_path_buf());
+        }
+        env::join_paths(paths.iter()).unwrap()
+    });
+}
+
+/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
+/// containing a `cmd: Command` field. The provided helpers are:
+///
+/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
+///    to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
+///    new specific helper methods over relying on these generic argument providers.
+/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
+///    methods of the same name on [`Command`].
+/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the
+///    command to finish running and returns the process's [`Output`]. `run` and `run_fail` are
+///    higher-level convenience methods which waits for the command to finish running and assert
+///    that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when
+///    possible.
+///
+/// Example usage:
+///
+/// ```ignore (illustrative)
+/// struct CommandWrapper { cmd: Command }
+///
+/// crate::impl_common_helpers!(CommandWrapper);
+///
+/// impl CommandWrapper {
+///     // ... additional specific helper methods
+/// }
+/// ```
+///
+/// [`Command`]: ::std::process::Command
+/// [`Output`]: ::std::process::Output
+macro_rules! impl_common_helpers {
+    ($wrapper: ident) => {
+        impl $wrapper {
+            /// Specify an environment variable.
+            pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
+            where
+                K: AsRef<::std::ffi::OsStr>,
+                V: AsRef<::std::ffi::OsStr>,
+            {
+                self.cmd.env(key, value);
+                self
+            }
+
+            /// Remove an environmental variable.
+            pub fn env_remove<K>(&mut self, key: K) -> &mut Self
+            where
+                K: AsRef<::std::ffi::OsStr>,
+            {
+                self.cmd.env_remove(key);
+                self
+            }
+
+            /// Clear all environmental variables.
+            pub fn env_var(&mut self) -> &mut Self {
+                self.cmd.env_clear();
+                self
+            }
+
+            /// Generic command argument provider. Prefer specific helper methods if possible.
+            /// Note that for some executables, arguments might be platform specific. For C/C++
+            /// compilers, arguments might be platform *and* compiler specific.
+            pub fn arg<S>(&mut self, arg: S) -> &mut Self
+            where
+                S: AsRef<::std::ffi::OsStr>,
+            {
+                self.cmd.arg(arg);
+                self
+            }
+
+            /// Generic command arguments provider. Prefer specific helper methods if possible.
+            /// Note that for some executables, arguments might be platform specific. For C/C++
+            /// compilers, arguments might be platform *and* compiler specific.
+            pub fn args<S>(&mut self, args: &[S]) -> &mut Self
+            where
+                S: AsRef<::std::ffi::OsStr>,
+            {
+                self.cmd.args(args);
+                self
+            }
+
+            /// Inspect what the underlying [`Command`][::std::process::Command] is up to the
+            /// current construction.
+            pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
+            where
+                I: FnOnce(&::std::process::Command),
+            {
+                inspector(&self.cmd);
+                self
+            }
+
+            /// Get the [`Output`][::std::process::Output] of the finished process.
+            pub fn output(&mut self) -> ::std::process::Output {
+                self.cmd.output().expect("failed to get output of finished process")
+            }
+
+            /// Run the constructed command and assert that it is successfully run.
+            #[track_caller]
+            pub fn run(&mut self) -> ::std::process::Output {
+                let caller_location = ::std::panic::Location::caller();
+                let caller_line_number = caller_location.line();
+
+                let output = self.cmd.output().unwrap();
+                if !output.status.success() {
+                    handle_failed_output(&self.cmd, output, caller_line_number);
+                }
+                output
+            }
+
+            /// Run the constructed command and assert that it does not successfully run.
+            #[track_caller]
+            pub fn run_fail(&mut self) -> ::std::process::Output {
+                let caller_location = ::std::panic::Location::caller();
+                let caller_line_number = caller_location.line();
+
+                let output = self.cmd.output().unwrap();
+                if output.status.success() {
+                    handle_failed_output(&self.cmd, output, caller_line_number);
+                }
+                output
+            }
+        }
+    };
+}
+
+pub(crate) use impl_common_helpers;
diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs
index e33ea9d6e40..9aad91f1b46 100644
--- a/src/tools/run-make-support/src/run.rs
+++ b/src/tools/run-make-support/src/run.rs
@@ -45,7 +45,7 @@ pub fn run(name: &str) -> Output {
 
     let (cmd, output) = run_common(name);
     if !output.status.success() {
-        handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
+        handle_failed_output(&cmd, output, caller_line_number);
     }
     output
 }
@@ -58,7 +58,7 @@ pub fn run_fail(name: &str) -> Output {
 
     let (cmd, output) = run_common(name);
     if output.status.success() {
-        handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
+        handle_failed_output(&cmd, output, caller_line_number);
     }
     output
 }
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 5a5b008a7cb..ebda151b908 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -1,9 +1,9 @@
 use std::env;
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsString;
 use std::path::Path;
 use std::process::{Command, Output};
 
-use crate::{handle_failed_output, tmp_dir};
+use crate::{handle_failed_output, set_host_rpath, tmp_dir};
 
 /// Construct a new `rustc` invocation.
 pub fn rustc() -> Rustc {
@@ -21,9 +21,12 @@ pub struct Rustc {
     cmd: Command,
 }
 
+crate::impl_common_helpers!(Rustc);
+
 fn setup_common() -> Command {
     let rustc = env::var("RUSTC").unwrap();
     let mut cmd = Command::new(rustc);
+    set_host_rpath(&mut cmd);
     cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir());
     cmd
 }
@@ -132,12 +135,6 @@ impl Rustc {
         self
     }
 
-    /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
-    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
-        self.cmd.arg(arg);
-        self
-    }
-
     /// Specify the crate type.
     pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
         self.cmd.arg("--crate-type");
@@ -152,49 +149,6 @@ impl Rustc {
         self
     }
 
-    /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
-    pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self {
-        self.cmd.args(args);
-        self
-    }
-
-    pub fn env(&mut self, name: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self {
-        self.cmd.env(name, value);
-        self
-    }
-
-    // Command inspection, output and running helper methods
-
-    /// Get the [`Output`][std::process::Output] of the finished `rustc` process.
-    pub fn output(&mut self) -> Output {
-        self.cmd.output().unwrap()
-    }
-
-    /// Run the constructed `rustc` command and assert that it is successfully run.
-    #[track_caller]
-    pub fn run(&mut self) -> Output {
-        let caller_location = std::panic::Location::caller();
-        let caller_line_number = caller_location.line();
-
-        let output = self.cmd.output().unwrap();
-        if !output.status.success() {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
-        }
-        output
-    }
-
-    #[track_caller]
-    pub fn run_fail(&mut self) -> Output {
-        let caller_location = std::panic::Location::caller();
-        let caller_line_number = caller_location.line();
-
-        let output = self.cmd.output().unwrap();
-        if output.status.success() {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
-        }
-        output
-    }
-
     #[track_caller]
     pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
         let caller_location = std::panic::Location::caller();
@@ -202,14 +156,8 @@ impl Rustc {
 
         let output = self.cmd.output().unwrap();
         if output.status.code().unwrap() != code {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+            handle_failed_output(&self.cmd, output, caller_line_number);
         }
         output
     }
-
-    /// Inspect what the underlying [`Command`] is up to the current construction.
-    pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
-        f(&self.cmd);
-        self
-    }
 }
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index 1fb4b589d76..1054ac83c10 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -1,9 +1,8 @@
 use std::env;
-use std::ffi::OsStr;
 use std::path::Path;
 use std::process::{Command, Output};
 
-use crate::handle_failed_output;
+use crate::{handle_failed_output, set_host_rpath};
 
 /// Construct a plain `rustdoc` invocation with no flags set.
 pub fn bare_rustdoc() -> Rustdoc {
@@ -20,9 +19,13 @@ pub struct Rustdoc {
     cmd: Command,
 }
 
+crate::impl_common_helpers!(Rustdoc);
+
 fn setup_common() -> Command {
     let rustdoc = env::var("RUSTDOC").unwrap();
-    Command::new(rustdoc)
+    let mut cmd = Command::new(rustdoc);
+    set_host_rpath(&mut cmd);
+    cmd
 }
 
 impl Rustdoc {
@@ -59,25 +62,6 @@ impl Rustdoc {
         self
     }
 
-    /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
-    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
-        self.cmd.arg(arg);
-        self
-    }
-
-    /// Run the build `rustdoc` command and assert that the run is successful.
-    #[track_caller]
-    pub fn run(&mut self) -> Output {
-        let caller_location = std::panic::Location::caller();
-        let caller_line_number = caller_location.line();
-
-        let output = self.cmd.output().unwrap();
-        if !output.status.success() {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
-        }
-        output
-    }
-
     #[track_caller]
     pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
         let caller_location = std::panic::Location::caller();
@@ -85,7 +69,7 @@ impl Rustdoc {
 
         let output = self.cmd.output().unwrap();
         if output.status.code().unwrap() != code {
-            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+            handle_failed_output(&self.cmd, output, caller_line_number);
         }
         output
     }
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 8c6b1eb22ec..58302b8e63b 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -6,7 +6,6 @@ autobins = false
 
 [dependencies]
 cargo_metadata = "0.15"
-cargo-platform = "0.1.2"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index aec2856dbbc..f380513f4ef 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,6 +1,6 @@
 //! Checks the licenses of third-party dependencies.
 
-use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
+use cargo_metadata::{Metadata, Package, PackageId};
 use std::collections::HashSet;
 use std::path::Path;
 
@@ -191,6 +191,7 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 /// rustc. Please check with the compiler team before adding an entry.
 const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
+    "addr2line",
     "adler",
     "ahash",
     "aho-corasick",
@@ -468,6 +469,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "mach",
     "memchr",
     "object",
+    "once_cell",
     "proc-macro2",
     "quote",
     "regalloc2",
@@ -668,27 +670,7 @@ fn check_permitted_dependencies(
     let mut deps = HashSet::new();
     for to_check in restricted_dependency_crates {
         let to_check = pkg_from_name(metadata, to_check);
-        use cargo_platform::Cfg;
-        use std::str::FromStr;
-        // We don't expect the compiler to ever run on wasm32, so strip
-        // out those dependencies to avoid polluting the permitted list.
-        deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
-            dep_kinds.iter().any(|dep_kind| {
-                dep_kind
-                    .target
-                    .as_ref()
-                    .map(|target| {
-                        !target.matches(
-                            "wasm32-unknown-unknown",
-                            &[
-                                Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
-                                Cfg::from_str("target_os=\"unknown\"").unwrap(),
-                            ],
-                        )
-                    })
-                    .unwrap_or(true)
-            })
-        });
+        deps_of(metadata, &to_check.id, &mut deps);
     }
 
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
@@ -740,18 +722,13 @@ fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId>
     let mut result = HashSet::new();
     for name in RUNTIME_CRATES {
         let id = &pkg_from_name(metadata, name).id;
-        deps_of_filtered(metadata, id, &mut result, &|_| true);
+        deps_of(metadata, id, &mut result);
     }
     result
 }
 
 /// Recursively find all dependencies.
-fn deps_of_filtered<'a>(
-    metadata: &'a Metadata,
-    pkg_id: &'a PackageId,
-    result: &mut HashSet<&'a PackageId>,
-    filter: &dyn Fn(&[DepKindInfo]) -> bool,
-) {
+fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) {
     if !result.insert(pkg_id) {
         return;
     }
@@ -764,9 +741,6 @@ fn deps_of_filtered<'a>(
         .find(|n| &n.id == pkg_id)
         .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     for dep in &node.deps {
-        if !filter(&dep.dep_kinds) {
-            continue;
-        }
-        deps_of_filtered(metadata, &dep.pkg, result, filter);
+        deps_of(metadata, &dep.pkg, result);
     }
 }
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index e14932ad99d..211dc347b0f 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1791,7 +1791,6 @@ ui/issues/issue-2150.rs
 ui/issues/issue-2151.rs
 ui/issues/issue-21546.rs
 ui/issues/issue-21554.rs
-ui/issues/issue-21596.rs
 ui/issues/issue-21600.rs
 ui/issues/issue-21622.rs
 ui/issues/issue-21634.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 78de8c0537d..7136bc4d8f2 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1722;
+const ISSUES_ENTRY_LIMIT: usize = 1720;
 const ROOT_ENTRY_LIMIT: usize = 859;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs
index 1b2bd4b3d81..3e2a4773703 100644
--- a/tests/assembly/asm/aarch64-types.rs
+++ b/tests/assembly/asm/aarch64-types.rs
@@ -1,8 +1,11 @@
+//@ revisions: aarch64 arm64ec
 //@ assembly-output: emit-asm
-//@ compile-flags: --target aarch64-unknown-linux-gnu
-//@ needs-llvm-components: aarch64
+//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc
+//@ [arm64ec] needs-llvm-components: aarch64
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
@@ -77,7 +80,7 @@ extern "C" {
     static extern_static: u8;
 }
 
-// CHECK-LABEL: sym_fn:
+// CHECK-LABEL: {{("#)?}}sym_fn{{"?}}
 // CHECK: //APP
 // CHECK: bl extern_func
 // CHECK: //NO_APP
@@ -86,7 +89,7 @@ pub unsafe fn sym_fn() {
     asm!("bl {}", sym extern_func);
 }
 
-// CHECK-LABEL: sym_static:
+// CHECK-LABEL: {{("#)?}}sym_static{{"?}}
 // CHECK: //APP
 // CHECK: adr x0, extern_static
 // CHECK: //NO_APP
@@ -96,7 +99,7 @@ pub unsafe fn sym_static() {
 }
 
 // Regression test for #75761
-// CHECK-LABEL: issue_75761:
+// CHECK-LABEL: {{("#)?}}issue_75761{{"?}}
 // CHECK: str {{.*}}x30
 // CHECK: //APP
 // CHECK: //NO_APP
@@ -144,421 +147,421 @@ macro_rules! check_reg {
     };
 }
 
-// CHECK-LABEL: reg_i8:
+// CHECK-LABEL: {{("#)?}}reg_i8{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i8 i8 reg "mov" "");
 
-// CHECK-LABEL: reg_i16:
+// CHECK-LABEL: {{("#)?}}reg_i16{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i16 i16 reg "mov" "");
 
-// CHECK-LABEL: reg_i32:
+// CHECK-LABEL: {{("#)?}}reg_i32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i32 i32 reg "mov" "");
 
-// CHECK-LABEL: reg_f32:
+// CHECK-LABEL: {{("#)?}}reg_f32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_f32 f32 reg "mov" "");
 
-// CHECK-LABEL: reg_i64:
+// CHECK-LABEL: {{("#)?}}reg_i64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i64 i64 reg "mov" "");
 
-// CHECK-LABEL: reg_f64:
+// CHECK-LABEL: {{("#)?}}reg_f64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_f64 f64 reg "mov" "");
 
-// CHECK-LABEL: reg_ptr:
+// CHECK-LABEL: {{("#)?}}reg_ptr{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_ptr ptr reg "mov" "");
 
-// CHECK-LABEL: vreg_i8:
+// CHECK-LABEL: {{("#)?}}vreg_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8 i8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16:
+// CHECK-LABEL: {{("#)?}}vreg_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16 i16 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32:
+// CHECK-LABEL: {{("#)?}}vreg_i32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32 i32 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32:
+// CHECK-LABEL: {{("#)?}}vreg_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32 f32 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64:
+// CHECK-LABEL: {{("#)?}}vreg_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64 i64 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64:
+// CHECK-LABEL: {{("#)?}}vreg_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64 f64 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_ptr:
+// CHECK-LABEL: {{("#)?}}vreg_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_ptr ptr vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i8x8:
+// CHECK-LABEL: {{("#)?}}vreg_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8x8 i8x8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16x4:
+// CHECK-LABEL: {{("#)?}}vreg_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16x4 i16x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32x2:
+// CHECK-LABEL: {{("#)?}}vreg_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32x2 i32x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64x1:
+// CHECK-LABEL: {{("#)?}}vreg_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64x1 i64x1 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32x2:
+// CHECK-LABEL: {{("#)?}}vreg_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32x2 f32x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64x1:
+// CHECK-LABEL: {{("#)?}}vreg_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64x1 f64x1 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i8x16:
+// CHECK-LABEL: {{("#)?}}vreg_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8x16 i8x16 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16x8:
+// CHECK-LABEL: {{("#)?}}vreg_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16x8 i16x8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32x4:
+// CHECK-LABEL: {{("#)?}}vreg_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32x4 i32x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64x2:
+// CHECK-LABEL: {{("#)?}}vreg_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64x2 i64x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32x4:
+// CHECK-LABEL: {{("#)?}}vreg_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32x4 f32x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64x2:
+// CHECK-LABEL: {{("#)?}}vreg_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64x2 f64x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_ptr:
+// CHECK-LABEL: {{("#)?}}vreg_low16_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8x8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i32x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64x1:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64x1:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8x16:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16x8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i32x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: x0_i8:
+// CHECK-LABEL: {{("#)?}}x0_i8{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i8 i8 "x0" "mov");
 
-// CHECK-LABEL: x0_i16:
+// CHECK-LABEL: {{("#)?}}x0_i16{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i16 i16 "x0" "mov");
 
-// CHECK-LABEL: x0_i32:
+// CHECK-LABEL: {{("#)?}}x0_i32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i32 i32 "x0" "mov");
 
-// CHECK-LABEL: x0_f32:
+// CHECK-LABEL: {{("#)?}}x0_f32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_f32 f32 "x0" "mov");
 
-// CHECK-LABEL: x0_i64:
+// CHECK-LABEL: {{("#)?}}x0_i64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i64 i64 "x0" "mov");
 
-// CHECK-LABEL: x0_f64:
+// CHECK-LABEL: {{("#)?}}x0_f64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_f64 f64 "x0" "mov");
 
-// CHECK-LABEL: x0_ptr:
+// CHECK-LABEL: {{("#)?}}x0_ptr{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_ptr ptr "x0" "mov");
 
-// CHECK-LABEL: v0_i8:
+// CHECK-LABEL: {{("#)?}}v0_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8 i8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16:
+// CHECK-LABEL: {{("#)?}}v0_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16 i16 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32:
+// CHECK-LABEL: {{("#)?}}v0_i32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32 i32 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32:
+// CHECK-LABEL: {{("#)?}}v0_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32 f32 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64:
+// CHECK-LABEL: {{("#)?}}v0_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64 i64 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64:
+// CHECK-LABEL: {{("#)?}}v0_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f64 f64 "s0" "fmov");
 
-// CHECK-LABEL: v0_ptr:
+// CHECK-LABEL: {{("#)?}}v0_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_ptr ptr "s0" "fmov");
 
-// CHECK-LABEL: v0_i8x8:
+// CHECK-LABEL: {{("#)?}}v0_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8x8 i8x8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16x4:
+// CHECK-LABEL: {{("#)?}}v0_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16x4 i16x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32x2:
+// CHECK-LABEL: {{("#)?}}v0_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32x2 i32x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64x1:
+// CHECK-LABEL: {{("#)?}}v0_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64x1 i64x1 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32x2:
+// CHECK-LABEL: {{("#)?}}v0_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32x2 f32x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64x1:
+// CHECK-LABEL: {{("#)?}}v0_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f64x1 f64x1 "s0" "fmov");
 
-// CHECK-LABEL: v0_i8x16:
+// CHECK-LABEL: {{("#)?}}v0_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8x16 i8x16 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16x8:
+// CHECK-LABEL: {{("#)?}}v0_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16x8 i16x8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32x4:
+// CHECK-LABEL: {{("#)?}}v0_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32x4 i32x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64x2:
+// CHECK-LABEL: {{("#)?}}v0_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64x2 i64x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32x4:
+// CHECK-LABEL: {{("#)?}}v0_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32x4 f32x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64x2:
+// CHECK-LABEL: {{("#)?}}v0_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs
index fab9f8632fc..86ec9d73afe 100644
--- a/tests/codegen/ascii-char.rs
+++ b/tests/codegen/ascii-char.rs
@@ -12,7 +12,7 @@ pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar {
     // CHECK-NOT: panic
 
     // CHECK: %[[R:.+]] = urem i32 %v, 10
-    // CHECK-NEXT: %[[T:.+]] = trunc i32 %[[R]] to i8
+    // CHECK-NEXT: %[[T:.+]] = trunc{{( nuw)?( nsw)?}} i32 %[[R]] to i8
     // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48
     // CHECK-NEXT: ret i8 %[[D]]
 
diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs
new file mode 100644
index 00000000000..807873ea368
--- /dev/null
+++ b/tests/codegen/cffi/c-variadic-naked.rs
@@ -0,0 +1,19 @@
+//@ needs-asm-support
+//@ only-x86_64
+
+// tests that `va_start` is not injected into naked functions
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![feature(naked_functions)]
+#![no_std]
+
+#[naked]
+pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
+    // CHECK-NOT: va_start
+    // CHECK-NOT: alloca
+    core::arch::asm! {
+        "ret",
+        options(noreturn),
+    }
+}
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
new file mode 100644
index 00000000000..97d545e0283
--- /dev/null
+++ b/tests/codegen/float/f128.rs
@@ -0,0 +1,129 @@
+// Verify that our intrinsics generate the correct LLVM calls for f128
+
+#![crate_type = "lib"]
+#![feature(f128)]
+#![feature(core_intrinsics)]
+
+// CHECK-LABEL: i1 @f128_eq(
+#[no_mangle]
+pub fn f128_eq(a: f128, b: f128) -> bool {
+    // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}}
+    a == b
+}
+
+// CHECK-LABEL: i1 @f128_ne(
+#[no_mangle]
+pub fn f128_ne(a: f128, b: f128) -> bool {
+    // CHECK: fcmp une fp128 %{{.+}}, %{{.+}}
+    a != b
+}
+
+// CHECK-LABEL: i1 @f128_gt(
+#[no_mangle]
+pub fn f128_gt(a: f128, b: f128) -> bool {
+    // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}}
+    a > b
+}
+
+// CHECK-LABEL: i1 @f128_ge(
+#[no_mangle]
+pub fn f128_ge(a: f128, b: f128) -> bool {
+    // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}}
+    a >= b
+}
+
+// CHECK-LABEL: i1 @f128_lt(
+#[no_mangle]
+pub fn f128_lt(a: f128, b: f128) -> bool {
+    // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}}
+    a < b
+}
+
+// CHECK-LABEL: i1 @f128_le(
+#[no_mangle]
+pub fn f128_le(a: f128, b: f128) -> bool {
+    // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}}
+    a <= b
+}
+
+// CHECK-LABEL: fp128 @f128_neg(
+#[no_mangle]
+pub fn f128_neg(a: f128) -> f128 {
+    // CHECK: fneg fp128
+    -a
+}
+
+// CHECK-LABEL: fp128 @f128_add(
+#[no_mangle]
+pub fn f128_add(a: f128, b: f128) -> f128 {
+    // CHECK: fadd fp128 %{{.+}}, %{{.+}}
+    a + b
+}
+
+// CHECK-LABEL: fp128 @f128_sub(
+#[no_mangle]
+pub fn f128_sub(a: f128, b: f128) -> f128 {
+    // CHECK: fsub fp128 %{{.+}}, %{{.+}}
+    a - b
+}
+
+// CHECK-LABEL: fp128 @f128_mul(
+#[no_mangle]
+pub fn f128_mul(a: f128, b: f128) -> f128 {
+    // CHECK: fmul fp128 %{{.+}}, %{{.+}}
+    a * b
+}
+
+// CHECK-LABEL: fp128 @f128_div(
+#[no_mangle]
+pub fn f128_div(a: f128, b: f128) -> f128 {
+    // CHECK: fdiv fp128 %{{.+}}, %{{.+}}
+    a / b
+}
+
+// CHECK-LABEL: fp128 @f128_rem(
+#[no_mangle]
+pub fn f128_rem(a: f128, b: f128) -> f128 {
+    // CHECK: frem fp128 %{{.+}}, %{{.+}}
+    a % b
+}
+
+// CHECK-LABEL: void @f128_add_assign(
+#[no_mangle]
+pub fn f128_add_assign(a: &mut f128, b: f128) {
+    // CHECK: fadd fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a += b;
+}
+
+// CHECK-LABEL: void @f128_sub_assign(
+#[no_mangle]
+pub fn f128_sub_assign(a: &mut f128, b: f128) {
+    // CHECK: fsub fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a -= b;
+}
+
+// CHECK-LABEL: void @f128_mul_assign(
+#[no_mangle]
+pub fn f128_mul_assign(a: &mut f128, b: f128) {
+    // CHECK: fmul fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a *= b
+}
+
+// CHECK-LABEL: void @f128_div_assign(
+#[no_mangle]
+pub fn f128_div_assign(a: &mut f128, b: f128) {
+    // CHECK: fdiv fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a /= b
+}
+
+// CHECK-LABEL: void @f128_rem_assign(
+#[no_mangle]
+pub fn f128_rem_assign(a: &mut f128, b: f128) {
+    // CHECK: frem fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a %= b
+}
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
new file mode 100644
index 00000000000..d1f75cc3b68
--- /dev/null
+++ b/tests/codegen/float/f16.rs
@@ -0,0 +1,129 @@
+// Verify that our intrinsics generate the correct LLVM calls for f16
+
+#![crate_type = "lib"]
+#![feature(f16)]
+#![feature(core_intrinsics)]
+
+// CHECK-LABEL: i1 @f16_eq(
+#[no_mangle]
+pub fn f16_eq(a: f16, b: f16) -> bool {
+    // CHECK: fcmp oeq half %{{.+}}, %{{.+}}
+    a == b
+}
+
+// CHECK-LABEL: i1 @f16_ne(
+#[no_mangle]
+pub fn f16_ne(a: f16, b: f16) -> bool {
+    // CHECK: fcmp une half %{{.+}}, %{{.+}}
+    a != b
+}
+
+// CHECK-LABEL: i1 @f16_gt(
+#[no_mangle]
+pub fn f16_gt(a: f16, b: f16) -> bool {
+    // CHECK: fcmp ogt half %{{.+}}, %{{.+}}
+    a > b
+}
+
+// CHECK-LABEL: i1 @f16_ge(
+#[no_mangle]
+pub fn f16_ge(a: f16, b: f16) -> bool {
+    // CHECK: fcmp oge half %{{.+}}, %{{.+}}
+    a >= b
+}
+
+// CHECK-LABEL: i1 @f16_lt(
+#[no_mangle]
+pub fn f16_lt(a: f16, b: f16) -> bool {
+    // CHECK: fcmp olt half %{{.+}}, %{{.+}}
+    a < b
+}
+
+// CHECK-LABEL: i1 @f16_le(
+#[no_mangle]
+pub fn f16_le(a: f16, b: f16) -> bool {
+    // CHECK: fcmp ole half %{{.+}}, %{{.+}}
+    a <= b
+}
+
+// CHECK-LABEL: half @f16_neg(
+#[no_mangle]
+pub fn f16_neg(a: f16) -> f16 {
+    // CHECK: fneg half %{{.+}}
+    -a
+}
+
+// CHECK-LABEL: half @f16_add(
+#[no_mangle]
+pub fn f16_add(a: f16, b: f16) -> f16 {
+    // CHECK: fadd half %{{.+}}, %{{.+}}
+    a + b
+}
+
+// CHECK-LABEL: half @f16_sub(
+#[no_mangle]
+pub fn f16_sub(a: f16, b: f16) -> f16 {
+    // CHECK: fsub half %{{.+}}, %{{.+}}
+    a - b
+}
+
+// CHECK-LABEL: half @f16_mul(
+#[no_mangle]
+pub fn f16_mul(a: f16, b: f16) -> f16 {
+    // CHECK: fmul half %{{.+}}, %{{.+}}
+    a * b
+}
+
+// CHECK-LABEL: half @f16_div(
+#[no_mangle]
+pub fn f16_div(a: f16, b: f16) -> f16 {
+    // CHECK: fdiv half %{{.+}}, %{{.+}}
+    a / b
+}
+
+// CHECK-LABEL: half @f16_rem(
+#[no_mangle]
+pub fn f16_rem(a: f16, b: f16) -> f16 {
+    // CHECK: frem half %{{.+}}, %{{.+}}
+    a % b
+}
+
+// CHECK-LABEL: void @f16_add_assign(
+#[no_mangle]
+pub fn f16_add_assign(a: &mut f16, b: f16) {
+    // CHECK: fadd half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a += b;
+}
+
+// CHECK-LABEL: void @f16_sub_assign(
+#[no_mangle]
+pub fn f16_sub_assign(a: &mut f16, b: f16) {
+    // CHECK: fsub half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a -= b;
+}
+
+// CHECK-LABEL: void @f16_mul_assign(
+#[no_mangle]
+pub fn f16_mul_assign(a: &mut f16, b: f16) {
+    // CHECK: fmul half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a *= b
+}
+
+// CHECK-LABEL: void @f16_div_assign(
+#[no_mangle]
+pub fn f16_div_assign(a: &mut f16, b: f16) {
+    // CHECK: fdiv half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a /= b
+}
+
+// CHECK-LABEL: void @f16_rem_assign(
+#[no_mangle]
+pub fn f16_rem_assign(a: &mut f16, b: f16) {
+    // CHECK: frem half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a %= b
+}
diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs
index 755dd155112..3c426825537 100644
--- a/tests/codegen/naked-fn/naked-functions.rs
+++ b/tests/codegen/naked-fn/naked-functions.rs
@@ -19,7 +19,7 @@ pub unsafe extern "C" fn naked_empty() {
 }
 
 // CHECK: Function Attrs: naked
-// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b)
+// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %0, i64 %1)
 #[no_mangle]
 #[naked]
 pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
index 7d020fbb4d2..86517c89627 100644
--- a/tests/codegen/unchecked_shifts.rs
+++ b/tests/codegen/unchecked_shifts.rs
@@ -22,7 +22,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
 
     // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
-    // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16
     // CHECK-DAG: shl i16 %a, %[[TRUNC]]
     a.unchecked_shl(b)
 }
@@ -54,7 +54,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
 
     // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
-    // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}}  i32 %b to i16
     // CHECK-DAG: ashr i16 %a, %[[TRUNC]]
     a.unchecked_shr(b)
 }
@@ -94,7 +94,7 @@ pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 {
 
     // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
-    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8
     // CHECK-DAG: shl i8 %a, %[[TRUNC]]
     std::intrinsics::unchecked_shl(a, b)
 }
@@ -107,7 +107,7 @@ pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 {
 
     // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
-    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8
     // CHECK-DAG: ashr i8 %a, %[[TRUNC]]
     std::intrinsics::unchecked_shr(a, b)
 }
diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs
index e5939470b46..92d6895143c 100644
--- a/tests/run-make/compiler-builtins/rmake.rs
+++ b/tests/run-make/compiler-builtins/rmake.rs
@@ -22,6 +22,7 @@ use run_make_support::object::read::Object;
 use run_make_support::object::ObjectSection;
 use run_make_support::object::ObjectSymbol;
 use run_make_support::object::RelocationTarget;
+use run_make_support::set_host_rpath;
 use run_make_support::tmp_dir;
 use std::collections::HashSet;
 
@@ -48,8 +49,8 @@ fn main() {
     let path = std::env::var("PATH").unwrap();
     let rustc = std::env::var("RUSTC").unwrap();
     let bootstrap_cargo = std::env::var("BOOTSTRAP_CARGO").unwrap();
-    let status = std::process::Command::new(bootstrap_cargo)
-        .args([
+    let mut cmd = std::process::Command::new(bootstrap_cargo);
+    cmd.args([
             "build",
             "--manifest-path",
             manifest_path.to_str().unwrap(),
@@ -62,10 +63,10 @@ fn main() {
         .env("RUSTC", rustc)
         .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes")
         .env("CARGO_TARGET_DIR", &target_dir)
-        .env("RUSTC_BOOTSTRAP", "1")
-        .status()
-        .unwrap();
+        .env("RUSTC_BOOTSTRAP", "1");
+    set_host_rpath(&mut cmd);
 
+    let status = cmd.status().unwrap();
     assert!(status.success());
 
     let rlibs_path = target_dir.join(target).join("debug").join("deps");
diff --git a/tests/run-make/rust-lld/Makefile b/tests/run-make/rust-lld/Makefile
index f8526530d4d..1ecac479f41 100644
--- a/tests/run-make/rust-lld/Makefile
+++ b/tests/run-make/rust-lld/Makefile
@@ -4,5 +4,9 @@ include ../tools.mk
 # needs-rust-lld
 # ignore-s390x lld does not yet support s390x as target
 all:
-	RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Clinker-flavor=gnu-lld-cc -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
+	RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
+	$(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
+
+	# while we're here, also check that the last linker feature flag "wins"
+	RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=-lld -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
 	$(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
diff --git a/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md b/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md
new file mode 100644
index 00000000000..b07717d8f02
--- /dev/null
+++ b/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md
@@ -0,0 +1,10 @@
+HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE!
+
+Normally, a line with errors on it will also have a comment
+marking it up as something that needs to generate an error.
+
+The test harness doesn't gather hot comments from this file.
+Rustdoc will generate an error for the line, and the `.stderr`
+snapshot includes this error, but Compiletest doesn't see it.
+
+If the stderr file changes, make sure the warning points at the URL!
diff --git a/tests/rustdoc-ui/include-str-bare-urls.rs b/tests/rustdoc-ui/include-str-bare-urls.rs
new file mode 100644
index 00000000000..c452c88cdd3
--- /dev/null
+++ b/tests/rustdoc-ui/include-str-bare-urls.rs
@@ -0,0 +1,15 @@
+// https://github.com/rust-lang/rust/issues/118549
+//
+// HEADS UP!
+//
+// Normally, a line with errors on it will also have a comment
+// marking it up as something that needs to generate an error.
+//
+// The test harness doesn't gather hot comments from the `.md` file.
+// Rustdoc will generate an error for the line, and the `.stderr`
+// snapshot includes this error, but Compiletest doesn't see it.
+//
+// If the stderr file changes, make sure the warning points at the URL!
+
+#![deny(rustdoc::bare_urls)]
+#![doc=include_str!("auxiliary/include-str-bare-urls.md")]
diff --git a/tests/rustdoc-ui/include-str-bare-urls.stderr b/tests/rustdoc-ui/include-str-bare-urls.stderr
new file mode 100644
index 00000000000..a4234196b23
--- /dev/null
+++ b/tests/rustdoc-ui/include-str-bare-urls.stderr
@@ -0,0 +1,15 @@
+error: this URL is not a hyperlink
+  --> $DIR/auxiliary/include-str-bare-urls.md:1:11
+   |
+LL | HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE!
+   |           ^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com>`
+   |
+   = note: bare URLs are not automatically turned into clickable links
+note: the lint level is defined here
+  --> $DIR/include-str-bare-urls.rs:14:9
+   |
+LL | #![deny(rustdoc::bare_urls)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/rustdoc-ui/intra-doc/warning.rs b/tests/rustdoc-ui/intra-doc/warning.rs
index 96b5c2b36a1..ed51b2fa41b 100644
--- a/tests/rustdoc-ui/intra-doc/warning.rs
+++ b/tests/rustdoc-ui/intra-doc/warning.rs
@@ -47,11 +47,11 @@ pub fn d() {}
 
 macro_rules! f {
     ($f:expr) => {
-        #[doc = $f] //~ WARNING `BarF`
+        #[doc = $f]
         pub fn f() {}
     }
 }
-f!("Foo\nbar [BarF] bar\nbaz");
+f!("Foo\nbar [BarF] bar\nbaz"); //~ WARNING `BarF`
 
 /** # for example,
  *
diff --git a/tests/rustdoc-ui/intra-doc/warning.stderr b/tests/rustdoc-ui/intra-doc/warning.stderr
index 19399a0df5b..3a06f1787e0 100644
--- a/tests/rustdoc-ui/intra-doc/warning.stderr
+++ b/tests/rustdoc-ui/intra-doc/warning.stderr
@@ -69,10 +69,10 @@ LL | bar [BarC] bar
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarD`
-  --> $DIR/warning.rs:45:1
+  --> $DIR/warning.rs:45:9
    |
 LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the link appears in this line:
            
@@ -82,13 +82,10 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarF`
-  --> $DIR/warning.rs:50:9
+  --> $DIR/warning.rs:54:4
    |
-LL |         #[doc = $f]
-   |         ^^^^^^^^^^^
-...
 LL | f!("Foo\nbar [BarF] bar\nbaz");
-   | ------------------------------ in this macro invocation
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the link appears in this line:
            
@@ -115,10 +112,10 @@ LL |  * time to introduce a link [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/warning.rs:68:1
+  --> $DIR/warning.rs:68:9
    |
 LL | #[doc = "single line [error]"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the link appears in this line:
            
@@ -128,10 +125,10 @@ LL | #[doc = "single line [error]"]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/warning.rs:71:1
+  --> $DIR/warning.rs:71:9
    |
 LL | #[doc = "single line with \"escaping\" [error]"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the link appears in this line:
            
diff --git a/tests/rustdoc-ui/invalid-syntax.stderr b/tests/rustdoc-ui/invalid-syntax.stderr
index 6140a06c555..46d7cdb4f7e 100644
--- a/tests/rustdoc-ui/invalid-syntax.stderr
+++ b/tests/rustdoc-ui/invalid-syntax.stderr
@@ -90,12 +90,13 @@ LL | | /// ```
    = note: error from rustc: unknown start of token: \
 
 warning: could not parse code block as Rust code
-  --> $DIR/invalid-syntax.rs:70:1
+  --> $DIR/invalid-syntax.rs:70:9
    |
-LL | / #[doc = "```"]
+LL |   #[doc = "```"]
+   |  _________^
 LL | | /// \_
 LL | | #[doc = "```"]
-   | |______________^
+   | |_____________^
    |
    = help: mark blocks that do not contain Rust code as text: ```text
    = note: error from rustc: unknown start of token: \
diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr
index 000a5b597d2..67b87f353a1 100644
--- a/tests/rustdoc-ui/unescaped_backticks.stderr
+++ b/tests/rustdoc-ui/unescaped_backticks.stderr
@@ -640,10 +640,10 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
    |                                                   +
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:108:1
+  --> $DIR/unescaped_backticks.rs:108:9
    |
 LL | #[doc = "`"]
-   | ^^^^^^^^^^^^
+   |         ^^^
    |
    = help: the opening or closing backtick of an inline code may be missing
    = help: if you meant to use a literal backtick, escape it
@@ -651,10 +651,10 @@ LL | #[doc = "`"]
            to this: \`
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:115:1
+  --> $DIR/unescaped_backticks.rs:115:9
    |
 LL | #[doc = concat!("\\", "`")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^
    |
    = help: the opening backtick of an inline code may be missing
             change: \`
@@ -664,10 +664,10 @@ LL | #[doc = concat!("\\", "`")]
            to this: \\`
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:119:1
+  --> $DIR/unescaped_backticks.rs:119:9
    |
 LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: the opening backtick of a previous inline code may be missing
             change: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
@@ -677,10 +677,10 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a
            to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`.
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:123:1
+  --> $DIR/unescaped_backticks.rs:123:9
    |
 LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a previous inline code might be longer than expected
             change: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
@@ -690,10 +690,10 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a
            to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`.
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:127:1
+  --> $DIR/unescaped_backticks.rs:127:9
    |
 LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: the opening backtick of an inline code may be missing
             change: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
@@ -703,10 +703,10 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same
            to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`.
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:131:1
+  --> $DIR/unescaped_backticks.rs:131:9
    |
 LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: the closing backtick of an inline code may be missing
             change: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs
index ec06f2f0c5d..2a3dd72749c 100644
--- a/tests/rustdoc/inline_cross/inline_hidden.rs
+++ b/tests/rustdoc/inline_cross/inline_hidden.rs
@@ -4,9 +4,23 @@
 
 extern crate rustdoc_hidden;
 
+// @has inline_hidden/index.html
+// Ensures this item is not inlined.
+// @has - '//*[@id="reexport.Foo"]/code' 'pub use rustdoc_hidden::Foo;'
 #[doc(no_inline)]
 pub use rustdoc_hidden::Foo;
 
+// Even if the foreign item has `doc(hidden)`, we should be able to inline it.
+// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined'
+#[doc(inline)]
+pub use rustdoc_hidden::Foo as Inlined;
+
+// Even with this import, we should not see `Foo`.
+// @count - '//*[@class="item-name"]' 4
+// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar'
+// @has - '//*[@class="item-name"]/a[@class="fn"]' 'foo'
+pub use rustdoc_hidden::*;
+
 // @has inline_hidden/fn.foo.html
 // @!has - '//a/@title' 'Foo'
 pub fn foo(_: Foo) {}
diff --git a/tests/ui/array-slice-vec/vector-no-ann.stderr b/tests/ui/array-slice-vec/vector-no-ann.stderr
index 24b6abfb342..716971eb120 100644
--- a/tests/ui/array-slice-vec/vector-no-ann.stderr
+++ b/tests/ui/array-slice-vec/vector-no-ann.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Vec<T>`
+error[E0282]: type annotations needed for `Vec<_>`
   --> $DIR/vector-no-ann.rs:2:9
    |
 LL |     let _foo = Vec::new();
diff --git a/tests/ui/asm/aarch64/type-check-2-2.stderr b/tests/ui/asm/aarch64/type-check-2-2.stderr
index 41f7c01dc82..760aaefac83 100644
--- a/tests/ui/asm/aarch64/type-check-2-2.stderr
+++ b/tests/ui/asm/aarch64/type-check-2-2.stderr
@@ -8,8 +8,8 @@ LL |         asm!("{}", in(reg) x);
    |
 help: consider assigning a value
    |
-LL |         let x: u64 = 0;
-   |                    +++
+LL |         let x: u64 = 42;
+   |                    ++++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-2-2.rs:22:9
@@ -21,8 +21,8 @@ LL |         asm!("{}", inout(reg) y);
    |
 help: consider assigning a value
    |
-LL |         let mut y: u64 = 0;
-   |                        +++
+LL |         let mut y: u64 = 42;
+   |                        ++++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-2-2.rs:28:13
diff --git a/tests/ui/asm/x86_64/type-check-5.stderr b/tests/ui/asm/x86_64/type-check-5.stderr
index 7970e76d6a1..4fb75993463 100644
--- a/tests/ui/asm/x86_64/type-check-5.stderr
+++ b/tests/ui/asm/x86_64/type-check-5.stderr
@@ -8,8 +8,8 @@ LL |         asm!("{}", in(reg) x);
    |
 help: consider assigning a value
    |
-LL |         let x: u64 = 0;
-   |                    +++
+LL |         let x: u64 = 42;
+   |                    ++++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-5.rs:18:9
@@ -21,8 +21,8 @@ LL |         asm!("{}", inout(reg) y);
    |
 help: consider assigning a value
    |
-LL |         let mut y: u64 = 0;
-   |                        +++
+LL |         let mut y: u64 = 42;
+   |                        ++++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-5.rs:24:13
diff --git a/tests/ui/associated-types/associated-types-outlives.rs b/tests/ui/associated-types/associated-types-outlives.rs
index 55c276280b9..245218067b4 100644
--- a/tests/ui/associated-types/associated-types-outlives.rs
+++ b/tests/ui/associated-types/associated-types-outlives.rs
@@ -3,10 +3,10 @@
 // fn body, causing this (invalid) code to be accepted.
 
 pub trait Foo<'a> {
-    type Bar;
+    type Bar: Clone;
 }
 
-impl<'a, T:'a> Foo<'a> for T {
+impl<'a, T: 'a> Foo<'a> for T {
     type Bar = &'a T;
 }
 
diff --git a/tests/ui/associated-types/associated-types-outlives.stderr b/tests/ui/associated-types/associated-types-outlives.stderr
index deeedd22266..c97af672c33 100644
--- a/tests/ui/associated-types/associated-types-outlives.stderr
+++ b/tests/ui/associated-types/associated-types-outlives.stderr
@@ -10,6 +10,11 @@ LL |         drop(x);
    |              ^ move out of `x` occurs here
 LL |         return f(y);
    |                  - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         's: loop { y = denormalise(&x).clone(); break }
+   |                                       ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr
index 4e432c0e702..fb0e63c207a 100644
--- a/tests/ui/associated-types/issue-25700.stderr
+++ b/tests/ui/associated-types/issue-25700.stderr
@@ -7,6 +7,12 @@ LL |     drop(t);
    |          - value moved here
 LL |     drop(t);
    |          ^ value used here after move
+   |
+note: if `S<()>` implemented `Clone`, you could clone the value
+  --> $DIR/issue-25700.rs:1:1
+   |
+LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
index 1990d0ffe2a..ffb97ca04ac 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
@@ -5,7 +5,6 @@ fn foo() -> Box<dyn std::future::Future<Output = u32>> {
     let x = 0u32;
     Box::new((async || x)())
     //~^ ERROR cannot return value referencing local variable `x`
-    //~| ERROR cannot return value referencing temporary value
 }
 
 fn main() {
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
index be67c78221a..4b1ce300b56 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
@@ -7,15 +7,6 @@ LL |     Box::new((async || x)())
    |     |        `x` is borrowed here
    |     returns a value referencing data owned by the current function
 
-error[E0515]: cannot return value referencing temporary value
-  --> $DIR/async-borrowck-escaping-closure-error.rs:6:5
-   |
-LL |     Box::new((async || x)())
-   |     ^^^^^^^^^------------^^^
-   |     |        |
-   |     |        temporary value created here
-   |     returns a value referencing data owned by the current function
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs
new file mode 100644
index 00000000000..8fc9924a12f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs
@@ -0,0 +1,23 @@
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+struct DropMe;
+
+trait Impossible {}
+fn trait_error<T: Impossible>() {}
+
+pub fn main() {
+    let b = DropMe;
+    let async_closure = async move || {
+        // Type error here taints the environment. This causes us to fallback all
+        // variables to `Error`. This means that when we compute the upvars for the
+        // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization`
+        // and `ExprUseVisitor`` will bail early when it sees error. This means
+        // that our underlying assumption that the parent and child captures are
+        // compatible ends up being broken, previously leading to an ICE.
+        trait_error::<()>();
+        //~^ ERROR the trait bound `(): Impossible` is not satisfied
+        let _b = b;
+    };
+}
diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr
new file mode 100644
index 00000000000..b4dc3e268bd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `(): Impossible` is not satisfied
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:19:23
+   |
+LL |         trait_error::<()>();
+   |                       ^^ the trait `Impossible` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:7:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `trait_error`
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:8:19
+   |
+LL | fn trait_error<T: Impossible>() {}
+   |                   ^^^^^^^^^^ required by this bound in `trait_error`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-closures/moro-example.rs b/tests/ui/async-await/async-closures/moro-example.rs
new file mode 100644
index 00000000000..5a8f42c7ca5
--- /dev/null
+++ b/tests/ui/async-await/async-closures/moro-example.rs
@@ -0,0 +1,43 @@
+//@ check-pass
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::{marker::PhantomData, sync::Mutex};
+
+type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+
+pub struct Scope<'scope, 'env: 'scope> {
+    enqueued: Mutex<Vec<BoxFuture<'scope, ()>>>,
+    phantom: PhantomData<&'env ()>,
+}
+
+impl<'scope, 'env: 'scope> Scope<'scope, 'env> {
+    pub fn spawn(&'scope self, future: impl Future<Output = ()> + Send + 'scope) {
+        self.enqueued.lock().unwrap().push(Box::pin(future));
+    }
+}
+
+fn scope_with_closure<'env, B>(_body: B) -> BoxFuture<'env, ()>
+where
+    for<'scope> B: async FnOnce(&'scope Scope<'scope, 'env>),
+{
+    todo!()
+}
+
+type ScopeRef<'scope, 'env> = &'scope Scope<'scope, 'env>;
+
+async fn go<'a>(value: &'a i32) {
+    let closure = async |scope: ScopeRef<'_, 'a>| {
+        let _future1 = scope.spawn(async {
+            // Make sure that `*value` is immutably borrowed with lifetime of
+            // `'a` and not with the lifetime of the containing coroutine-closure.
+            let _v = *value;
+        });
+    };
+    scope_with_closure(closure).await;
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/no-borrow-from-env.rs b/tests/ui/async-await/async-closures/no-borrow-from-env.rs
new file mode 100644
index 00000000000..fe84aeeb32f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/no-borrow-from-env.rs
@@ -0,0 +1,44 @@
+//@ edition: 2021
+//@ check-pass
+
+#![feature(async_closure)]
+
+fn outlives<'a>(_: impl Sized + 'a) {}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+fn simple<'a>(x: &'a i32) {
+    let c = async || { println!("{}", *x); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+}
+
+struct S<'a>(&'a i32);
+
+fn through_field<'a>(x: S<'a>) {
+    let c = async || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+}
+
+fn through_field_and_ref<'a>(x: &S<'a>) {
+    let c = async || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs
new file mode 100644
index 00000000000..17681161e20
--- /dev/null
+++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs
@@ -0,0 +1,47 @@
+//@ edition: 2018
+
+// This is `no-borrow-from-env.rs`, but under edition 2018 we still want to make
+// sure that we don't ICE or anything, even if precise closure captures means
+// that we can't actually borrowck successfully.
+
+#![feature(async_closure)]
+
+fn outlives<'a>(_: impl Sized + 'a) {}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+fn simple<'a>(x: &'a i32) {
+    let c = async || { println!("{}", *x); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x); };
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c`
+}
+
+struct S<'a>(&'a i32);
+
+fn through_field<'a>(x: S<'a>) {
+    let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); }; //~ ERROR cannot move out of `x`
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c`
+}
+
+fn through_field_and_ref<'a>(x: &S<'a>) {
+    let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c)); //~ ERROR explicit lifetime required in the type of `x`
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
new file mode 100644
index 00000000000..569028934cb
--- /dev/null
+++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
@@ -0,0 +1,152 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:16:13
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:21:20
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0505]: cannot move out of `c` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:22:30
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ---
+   |                    |
+   |                    borrow of `c` occurs here
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+   |                              ^ move out of `c` occurs here
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:28:13
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:32:13
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ---------------------------------- borrow of `x` occurs here
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+LL |
+LL |     let c = async move || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `x` occurs here
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:33:20
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0505]: cannot move out of `c` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:34:30
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ---
+   |                    |
+   |                    borrow of `c` occurs here
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+   |                              ^ move out of `c` occurs here
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:38:13
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                          -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/without-precise-captures-we-are-powerless.rs:40:20
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                                 ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
+...
+LL |     outlives::<'a>(call_once(c));
+   |                    ^^^^^^^^^^^^ lifetime `'a` required
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:43:20
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                          -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+LL | }
+   | - `c` dropped here while still borrowed
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0505, E0597, E0621.
+For more information about an error, try `rustc --explain E0505`.
diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs
new file mode 100644
index 00000000000..8ad99a4c201
--- /dev/null
+++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs
@@ -0,0 +1,17 @@
+//@ edition: 2021
+
+fn call(_: impl Fn() -> bool) {}
+
+async fn test() {
+    call(|| -> Option<()> {
+        //~^ ERROR expected
+        if true {
+            false
+            //~^ ERROR mismatched types
+        }
+        true
+        //~^ ERROR mismatched types
+    })
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
new file mode 100644
index 00000000000..70cd9f924ac
--- /dev/null
+++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
@@ -0,0 +1,46 @@
+error[E0308]: mismatched types
+  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:9:13
+   |
+LL | /         if true {
+LL | |             false
+   | |             ^^^^^ expected `()`, found `bool`
+LL | |
+LL | |         }
+   | |_________- expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9
+   |
+LL |         true
+   |         ^^^^ expected `Option<()>`, found `bool`
+   |
+   = note: expected enum `Option<()>`
+              found type `bool`
+
+error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>`
+  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10
+   |
+LL |       call(|| -> Option<()> {
+   |  _____----_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |         if true {
+LL | |             false
+...  |
+LL | |
+LL | |     })
+   | |_____^ expected `bool`, found `Option<()>`
+   |
+   = note: expected type `bool`
+              found enum `Option<()>`
+note: required by a bound in `call`
+  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:3:25
+   |
+LL | fn call(_: impl Fn() -> bool) {}
+   |                         ^^^^ required by this bound in `call`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0271, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr
index 92f38d5a796..640d946421a 100644
--- a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr
+++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr
@@ -62,7 +62,7 @@ error[E0308]: mismatched types
   --> $DIR/async-closure-gate.rs:27:5
    |
 LL |   fn foo3() {
-   |            - help: a return type might be missing here: `-> _`
+   |            - help: try adding a return type: `-> impl Future<Output = ()>`
 LL | /     async {
 LL | |
 LL | |         let _ = #[track_caller] || {
@@ -78,7 +78,7 @@ error[E0308]: mismatched types
   --> $DIR/async-closure-gate.rs:44:5
    |
 LL |   fn foo5() {
-   |            - help: a return type might be missing here: `-> _`
+   |            - help: try adding a return type: `-> impl Future<Output = ()>`
 LL | /     async {
 LL | |
 LL | |         let _ = || {
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr
index 92f38d5a796..640d946421a 100644
--- a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr
+++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr
@@ -62,7 +62,7 @@ error[E0308]: mismatched types
   --> $DIR/async-closure-gate.rs:27:5
    |
 LL |   fn foo3() {
-   |            - help: a return type might be missing here: `-> _`
+   |            - help: try adding a return type: `-> impl Future<Output = ()>`
 LL | /     async {
 LL | |
 LL | |         let _ = #[track_caller] || {
@@ -78,7 +78,7 @@ error[E0308]: mismatched types
   --> $DIR/async-closure-gate.rs:44:5
    |
 LL |   fn foo5() {
-   |            - help: a return type might be missing here: `-> _`
+   |            - help: try adding a return type: `-> impl Future<Output = ()>`
 LL | /     async {
 LL | |
 LL | |         let _ = || {
diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/augmented-assignments.rs
index bd2435a78bf..8b263e03593 100644
--- a/tests/ui/augmented-assignments.rs
+++ b/tests/ui/augmented-assignments.rs
@@ -1,5 +1,6 @@
 use std::ops::AddAssign;
 
+#[derive(Clone)]
 struct Int(i32);
 
 impl AddAssign for Int {
@@ -16,6 +17,7 @@ fn main() {
     x;
     //~^ ERROR cannot move out of `x` because it is borrowed
     //~| move out of `x` occurs here
+    //~| HELP consider cloning
 
     let y = Int(2);
     //~^ HELP consider changing this to be mutable
diff --git a/tests/ui/augmented-assignments.stderr b/tests/ui/augmented-assignments.stderr
index d1096aea279..6b2900dd5d1 100644
--- a/tests/ui/augmented-assignments.stderr
+++ b/tests/ui/augmented-assignments.stderr
@@ -1,5 +1,5 @@
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/augmented-assignments.rs:16:5
+  --> $DIR/augmented-assignments.rs:17:5
    |
 LL |     let mut x = Int(1);
    |         ----- binding `x` declared here
@@ -8,9 +8,14 @@ LL |     x
 ...
 LL |     x;
    |     ^ move out of `x` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     x.clone();
+   |      ++++++++
 
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
-  --> $DIR/augmented-assignments.rs:23:5
+  --> $DIR/augmented-assignments.rs:25:5
    |
 LL |     y
    |     ^ cannot borrow as mutable
diff --git a/tests/ui/binop/issue-77910-1.stderr b/tests/ui/binop/issue-77910-1.stderr
index 6402e568188..74deac900d4 100644
--- a/tests/ui/binop/issue-77910-1.stderr
+++ b/tests/ui/binop/issue-77910-1.stderr
@@ -32,8 +32,8 @@ LL |     xs
    |
 help: consider assigning a value
    |
-LL |     let xs = todo!();
-   |            +++++++++
+LL |     let xs = &42;
+   |            +++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/binop/issue-77910-2.stderr b/tests/ui/binop/issue-77910-2.stderr
index a14560ff188..7087f2cdf41 100644
--- a/tests/ui/binop/issue-77910-2.stderr
+++ b/tests/ui/binop/issue-77910-2.stderr
@@ -21,8 +21,8 @@ LL |     xs
    |
 help: consider assigning a value
    |
-LL |     let xs = todo!();
-   |            +++++++++
+LL |     let xs = &42;
+   |            +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/binop/multiply-is-deref-on-rhs.rs b/tests/ui/binop/multiply-is-deref-on-rhs.rs
new file mode 100644
index 00000000000..7c24e1b4d57
--- /dev/null
+++ b/tests/ui/binop/multiply-is-deref-on-rhs.rs
@@ -0,0 +1,8 @@
+pub fn test(y: &i32) {
+    let x;
+    x = ()
+    *y
+    //~^ ERROR cannot multiply `()` by `&i32`
+}
+
+fn main() {}
diff --git a/tests/ui/binop/multiply-is-deref-on-rhs.stderr b/tests/ui/binop/multiply-is-deref-on-rhs.stderr
new file mode 100644
index 00000000000..e157f4f58ca
--- /dev/null
+++ b/tests/ui/binop/multiply-is-deref-on-rhs.stderr
@@ -0,0 +1,16 @@
+error[E0369]: cannot multiply `()` by `&i32`
+  --> $DIR/multiply-is-deref-on-rhs.rs:4:5
+   |
+LL |     x = ()
+   |         -- ()
+LL |     *y
+   |     ^- &i32
+   |
+help: you might have meant to write a semicolon here
+   |
+LL |     x = ();
+   |           +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/borrowck/argument_number_mismatch_ice.stderr b/tests/ui/borrowck/argument_number_mismatch_ice.stderr
index 2a6a6dbc64c..702cebb86ba 100644
--- a/tests/ui/borrowck/argument_number_mismatch_ice.stderr
+++ b/tests/ui/borrowck/argument_number_mismatch_ice.stderr
@@ -12,6 +12,11 @@ error[E0594]: cannot assign to `*input`, which is behind a `&` reference
    |
 LL |         *input = self.0;
    |         ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
+   |
+LL |     fn example(&self, input: &mut i32) {
+   |                               +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr
index e324ebfb50f..8ea7a9a4989 100644
--- a/tests/ui/borrowck/borrow-tuple-fields.stderr
+++ b/tests/ui/borrowck/borrow-tuple-fields.stderr
@@ -10,6 +10,12 @@ LL |     let y = x;
 LL |
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let r = &x.0;
+LL +     let r = x.0.clone();
+   |
 
 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
   --> $DIR/borrow-tuple-fields.rs:18:13
@@ -42,6 +48,12 @@ LL |     let y = x;
    |             ^ move out of `x` occurs here
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let r = &x.0;
+LL +     let r = x.0.clone();
+   |
 
 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
   --> $DIR/borrow-tuple-fields.rs:33:13
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
index e582ec605de..b96949fbb0e 100644
--- a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
@@ -10,6 +10,12 @@ LL |         &*a,
    |         --- borrow of `*a` occurs here
 LL |         a);
    |         ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         &*a,
+LL +         a.clone(),
+   |
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@@ -22,6 +28,12 @@ LL |         &*a,
    |         --- borrow of `*a` occurs here
 LL |         a);
    |         ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         &*a,
+LL +         a.clone(),
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-block-uninit.stderr b/tests/ui/borrowck/borrowck-block-uninit.stderr
index 07c09f1f443..4db98a7a0dc 100644
--- a/tests/ui/borrowck/borrowck-block-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-block-uninit.stderr
@@ -10,8 +10,8 @@ LL |         println!("{}", x);
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
index 7c0cda31c97..e23ca534e74 100644
--- a/tests/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr
index 0d879c6fb7d..0367d224f80 100644
--- a/tests/ui/borrowck/borrowck-break-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-break-uninit.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr
index 411d85b8e05..9066891d298 100644
--- a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr
+++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr
@@ -38,6 +38,11 @@ LL |         let [y, z @ ..] = x;
 LL |     };
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let [y, z @ ..] = x.clone();
+   |                            ++++++++
 
 error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-closures-slice-patterns.rs:33:13
@@ -79,6 +84,12 @@ LL |         let [y, z @ ..] = *x;
 LL |     };
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         let [y, z @ ..] = *x;
+LL +         let [y, z @ ..] = x.clone();
+   |
 
 error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-closures-slice-patterns.rs:59:13
diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
index 11812847dd1..ea552ff7820 100644
--- a/tests/ui/borrowck/borrowck-field-sensitivity.stderr
+++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
@@ -49,6 +49,12 @@ LL |     drop(x.b);
    |          ^^^ move out of `x.b` occurs here
 LL |     drop(**p);
    |          --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p = &x.b;
+LL +     let p = x.b.clone();
+   |
 
 error[E0505]: cannot move out of `x.b` because it is borrowed
   --> $DIR/borrowck-field-sensitivity.rs:41:14
@@ -61,6 +67,12 @@ LL |     let _y = A { a: 3, .. x };
    |              ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
 LL |     drop(**p);
    |          --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p = &x.b;
+LL +     let p = x.b.clone();
+   |
 
 error[E0499]: cannot borrow `x.a` as mutable more than once at a time
   --> $DIR/borrowck-field-sensitivity.rs:48:13
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.rs b/tests/ui/borrowck/borrowck-fn-in-const-a.rs
index d4ceae2963b..d52ec342b1a 100644
--- a/tests/ui/borrowck/borrowck-fn-in-const-a.rs
+++ b/tests/ui/borrowck/borrowck-fn-in-const-a.rs
@@ -9,4 +9,5 @@ const MOVE: fn(&String) -> String = {
 };
 
 fn main() {
+    println!("{}", MOVE(&String::new()));
 }
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr
index e05696864fd..7bf0f859fdd 100644
--- a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr
+++ b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr
@@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*x` which is behind a shared reference
    |
 LL |         return *x
    |                ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         return *x
+LL +         return x.clone()
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-in-static.rs b/tests/ui/borrowck/borrowck-in-static.rs
index a45f7b18e07..864dff40f46 100644
--- a/tests/ui/borrowck/borrowck-in-static.rs
+++ b/tests/ui/borrowck/borrowck-in-static.rs
@@ -1,6 +1,6 @@
 // check that borrowck looks inside consts/statics
 
-static FN : &'static (dyn Fn() -> (Box<dyn Fn()->Box<i32>>) + Sync) = &|| {
+static FN : &'static (dyn Fn() -> Box<dyn Fn()->Box<i32>> + Sync) = &|| {
     let x = Box::new(0);
     Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure
 };
diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr
index 8171e6950ac..745b02ae21b 100644
--- a/tests/ui/borrowck/borrowck-in-static.stderr
+++ b/tests/ui/borrowck/borrowck-in-static.stderr
@@ -7,6 +7,11 @@ LL |     Box::new(|| x)
    |              -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
    |              |
    |              captured by this `Fn` closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     Box::new(|| x.clone())
+   |                  ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
index a27b6956b30..bfe3c60a84a 100644
--- a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -8,8 +8,8 @@ LL |         i
    |
 help: consider assigning a value
    |
-LL |         let i: isize = 0;
-   |                      +++
+LL |         let i: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
index 16f4c40f529..a248a6d85b6 100644
--- a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -8,8 +8,8 @@ LL |         i
    |
 help: consider assigning a value
    |
-LL |         let i: isize = 0;
-   |                      +++
+LL |         let i: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-fru.stderr b/tests/ui/borrowck/borrowck-init-in-fru.stderr
index f27993e10b4..b5c332a90bc 100644
--- a/tests/ui/borrowck/borrowck-init-in-fru.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-fru.stderr
@@ -8,8 +8,8 @@ LL |     origin = Point { x: 10, ..origin };
    |
 help: consider assigning a value
    |
-LL |     let mut origin: Point = todo!();
-   |                           +++++++++
+LL |     let mut origin: Point = value;
+   |                           +++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-op-equal.stderr b/tests/ui/borrowck/borrowck-init-op-equal.stderr
index 241d24341cb..d621c4ab46e 100644
--- a/tests/ui/borrowck/borrowck-init-op-equal.stderr
+++ b/tests/ui/borrowck/borrowck-init-op-equal.stderr
@@ -8,8 +8,8 @@ LL |     v += 1;
    |
 help: consider assigning a value
    |
-LL |     let v: isize = 0;
-   |                  +++
+LL |     let v: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.stderr b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
index 65de6e8bf5d..109321386ba 100644
--- a/tests/ui/borrowck/borrowck-init-plus-equal.stderr
+++ b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -8,8 +8,8 @@ LL |     v = v + 1;
    |
 help: consider assigning a value
    |
-LL |     let mut v: isize = 0;
-   |                      +++
+LL |     let mut v: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.fixed b/tests/ui/borrowck/borrowck-issue-2657-2.fixed
index e5aaf7d2de7..e532aa3e68c 100644
--- a/tests/ui/borrowck/borrowck-issue-2657-2.fixed
+++ b/tests/ui/borrowck/borrowck-issue-2657-2.fixed
@@ -5,7 +5,7 @@ fn main() {
 
     match x {
       Some(ref y) => {
-        let _b = y; //~ ERROR cannot move out
+        let _b = y.clone(); //~ ERROR cannot move out
       }
       _ => {}
     }
diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.stderr b/tests/ui/borrowck/borrowck-issue-2657-2.stderr
index 6fab19000fc..16186792b93 100644
--- a/tests/ui/borrowck/borrowck-issue-2657-2.stderr
+++ b/tests/ui/borrowck/borrowck-issue-2657-2.stderr
@@ -9,6 +9,11 @@ help: consider removing the dereference here
 LL -         let _b = *y;
 LL +         let _b = y;
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         let _b = *y;
+LL +         let _b = y.clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-issue-48962.stderr b/tests/ui/borrowck/borrowck-issue-48962.stderr
index ee174f6736e..6e821a4c6b0 100644
--- a/tests/ui/borrowck/borrowck-issue-48962.stderr
+++ b/tests/ui/borrowck/borrowck-issue-48962.stderr
@@ -17,6 +17,11 @@ LL |     {src};
    |      --- value moved here
 LL |     src.0 = 66;
    |     ^^^^^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     {src.clone()};
+   |         ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
index 86479043a06..370ae058f44 100644
--- a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
@@ -13,6 +13,12 @@ LL |         println!("v={}", *v);
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let w = &v;
+LL +     let w = v.clone();
+   |
 
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@@ -29,6 +35,12 @@ LL |         println!("v={}", *v);
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let w = &v;
+LL +     let w = v.clone();
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
index d1fbc5b47db..8a8005dbb83 100644
--- a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
@@ -9,6 +9,12 @@ LL |     take(v);
    |          ^ move out of `v` occurs here
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let w = &v;
+LL +     let w = v.clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
index a41c4af98e7..a23a203d999 100644
--- a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
+++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
@@ -10,6 +10,12 @@ LL |     let z = *a;
    |             ^^ move out of `*a` occurs here
 LL |     b.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let b = &a;
+LL +     let b = a.clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
index 7213f85ad98..ebc3b6ebcac 100644
--- a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
+++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
@@ -9,6 +9,11 @@ help: consider removing the dereference here
 LL -     let y = *x;
 LL +     let y = x;
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = *x;
+LL +     let y = x.clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
index 88eb6c8ceee..acf426906c3 100644
--- a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
+++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
@@ -10,6 +10,12 @@ LL |     let t1 = t0;
 LL |     *t1 = 22;
 LL |     p.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p: &isize = &*t0; // Freezes `*t0`
+LL +     let p: &isize = t0.clone(); // Freezes `*t0`
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed
index 8d5ebbc7744..a19db7e5cd3 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed
@@ -2,6 +2,6 @@
 use std::rc::Rc;
 
 pub fn main() {
-    let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
+    let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2]).clone()).into_iter();
     //~^ ERROR [E0507]
 }
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
index 076f0ce3440..577c2de38be 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
@@ -12,6 +12,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |     let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
    |              ++++++++++++++++++++++++++++                   +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _x = Rc::new(vec![1, 2]).clone().into_iter();
+   |                                 ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
index dce1f4d0775..774aac3ec9c 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
@@ -9,6 +9,11 @@ help: consider removing the dereference here
 LL -     let _x = *Rc::new("hi".to_string());
 LL +     let _x = Rc::new("hi".to_string());
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let _x = *Rc::new("hi".to_string());
+LL +     let _x = Rc::new("hi".to_string()).clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs
index d01fb261894..b24d9b932cd 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs
@@ -8,7 +8,8 @@ static BAR: Foo = Foo { foo: 5 };
 
 
 fn test(f: Foo) {
-    let _f = Foo{foo: 4, ..f};
+    let f = Foo { foo: 4, ..f };
+    println!("{}", f.foo);
 }
 
 fn main() {
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
index 07dcaf875e7..86bddacbdc7 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
@@ -1,8 +1,14 @@
 error[E0507]: cannot move out of static item `BAR`
-  --> $DIR/borrowck-move-out-of-static-item.rs:15:10
+  --> $DIR/borrowck-move-out-of-static-item.rs:16:10
    |
 LL |     test(BAR);
    |          ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrowck-move-out-of-static-item.rs:3:1
+   |
+LL | struct Foo {
+   | ^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
index 8408d99156a..4d9477f8581 100644
--- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
@@ -9,6 +9,12 @@ LL |   let S { x: ax } = a;
    |              ^^ move out of `a.x` occurs here
 LL |   f(pb);
    |     -- borrow later used here
+   |
+note: if `S` implemented `Clone`, you could clone the value
+  --> $DIR/borrowck-move-subcomponent.rs:6:1
+   |
+LL | struct S {
+   | ^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr
index 70abe7b346e..fdac4c27cee 100644
--- a/tests/ui/borrowck/borrowck-multiple-captures.stderr
+++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr
@@ -14,6 +14,12 @@ LL |         drop(x1);
 ...
 LL |     borrow(&*p1);
    |            ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p1 = &x1;
+LL +     let p1 = x1.clone();
+   |
 
 error[E0505]: cannot move out of `x2` because it is borrowed
   --> $DIR/borrowck-multiple-captures.rs:12:19
@@ -30,6 +36,12 @@ LL |         drop(x2);
 ...
 LL |     borrow(&*p2);
    |            ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p2 = &x2;
+LL +     let p2 = x2.clone();
+   |
 
 error[E0382]: use of moved value: `x1`
   --> $DIR/borrowck-multiple-captures.rs:27:19
@@ -93,6 +105,12 @@ LL |         drop(x);
 ...
 LL |     borrow(&*p);
    |            --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let p = &x;
+LL +     let p = x.clone();
+   |
 
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-multiple-captures.rs:52:14
diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr
index 723b19f4124..1602058c183 100644
--- a/tests/ui/borrowck/borrowck-overloaded-call.stderr
+++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr
@@ -29,6 +29,12 @@ LL |     s(" world".to_string());
    |     - value moved here
 LL |     s(" world".to_string());
    |     ^ value used here after move
+   |
+note: if `SFnOnce` implemented `Clone`, you could clone the value
+  --> $DIR/borrowck-overloaded-call.rs:41:1
+   |
+LL | struct SFnOnce {
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr
index b4106702cd1..3e874ed1a2f 100644
--- a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr
+++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr
@@ -8,6 +8,10 @@ help: consider borrowing here
    |
 LL |     let bad = &v[0];
    |               +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let bad = v[0].clone();
+   |                   ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-return.stderr b/tests/ui/borrowck/borrowck-return.stderr
index a1bc3008ea8..f680b9af4f0 100644
--- a/tests/ui/borrowck/borrowck-return.stderr
+++ b/tests/ui/borrowck/borrowck-return.stderr
@@ -8,8 +8,8 @@ LL |     return x;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-storage-dead.stderr b/tests/ui/borrowck/borrowck-storage-dead.stderr
index a08e2a7b535..5f29c61c7eb 100644
--- a/tests/ui/borrowck/borrowck-storage-dead.stderr
+++ b/tests/ui/borrowck/borrowck-storage-dead.stderr
@@ -8,8 +8,8 @@ LL |         let _ = x + 1;
    |
 help: consider assigning a value
    |
-LL |         let x: i32 = 0;
-   |                    +++
+LL |         let x: i32 = 42;
+   |                    ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs
index 1f6ed6d46aa..f0d067477c6 100644
--- a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs
+++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs
@@ -2,20 +2,63 @@
 // move, when the struct implements Drop.
 
 struct B;
-struct S { a: isize, b: B }
-impl Drop for S { fn drop(&mut self) { } }
+struct S<K> { a: isize, b: B, c: K }
+impl<K> Drop for S<K> { fn drop(&mut self) { } }
 
-struct T { a: isize, mv: Box<isize> }
+struct T { a: isize, b: Box<isize> }
 impl Drop for T { fn drop(&mut self) { } }
 
-fn f(s0:S) {
-    let _s2 = S{a: 2, ..s0};
-    //~^ ERROR [E0509]
+struct V<K> { a: isize, b: Box<isize>, c: K }
+impl<K> Drop for V<K> { fn drop(&mut self) { } }
+
+#[derive(Clone)]
+struct Clonable;
+
+mod not_all_clone {
+    use super::*;
+    fn a(s0: S<()>) {
+        let _s2 = S { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+    }
+    fn b(s0: S<B>) {
+        let _s2 = S { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+        //~| ERROR [E0509]
+    }
+    fn c<K: Clone>(s0: S<K>) {
+        let _s2 = S { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+        //~| ERROR [E0509]
+    }
 }
+mod all_clone {
+    use super::*;
+    fn a(s0: T) {
+        let _s2 = T { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+    }
+
+    fn b(s0: T) {
+        let _s2 = T { ..s0 };
+        //~^ ERROR [E0509]
+    }
+
+    fn c(s0: T) {
+        let _s2 = T { a: 2, b: s0.b };
+        //~^ ERROR [E0509]
+    }
+
+    fn d<K: Clone>(s0: V<K>) {
+        let _s2 = V { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+        //~| ERROR [E0509]
+    }
 
-fn g(s0:T) {
-    let _s2 = T{a: 2, ..s0};
-    //~^ ERROR [E0509]
+    fn e(s0: V<Clonable>) {
+        let _s2 = V { a: 2, ..s0 };
+        //~^ ERROR [E0509]
+        //~| ERROR [E0509]
+    }
 }
 
 fn main() { }
diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr
index af32f279100..bc11204acf2 100644
--- a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr
+++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr
@@ -1,21 +1,191 @@
-error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
-  --> $DIR/borrowck-struct-update-with-dtor.rs:12:15
+error[E0509]: cannot move out of type `S<()>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:20:19
    |
-LL |     let _s2 = S{a: 2, ..s0};
-   |               ^^^^^^^^^^^^^
-   |               |
-   |               cannot move out of here
-   |               move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
+LL |         let _s2 = S { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
+   |
+note: `B` doesn't implement `Copy` or `Clone`
+  --> $DIR/borrowck-struct-update-with-dtor.rs:4:1
+   |
+LL | struct B;
+   | ^^^^^^^^
+help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = S { a: 2, b: s0.b.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:24:19
+   |
+LL |         let _s2 = S { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
+   |
+note: `B` doesn't implement `Copy` or `Clone`
+  --> $DIR/borrowck-struct-update-with-dtor.rs:4:1
+   |
+LL | struct B;
+   | ^^^^^^^^
+help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() };
+   |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:24:19
+   |
+LL |         let _s2 = S { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.c` has type `B`, which does not implement the `Copy` trait
+   |
+note: `B` doesn't implement `Copy` or `Clone`
+  --> $DIR/borrowck-struct-update-with-dtor.rs:4:1
+   |
+LL | struct B;
+   | ^^^^^^^^
+help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() };
+   |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:29:19
+   |
+LL |         let _s2 = S { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
+   |
+note: `B` doesn't implement `Copy` or `Clone`
+  --> $DIR/borrowck-struct-update-with-dtor.rs:4:1
+   |
+LL | struct B;
+   | ^^^^^^^^
+help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = S { a: 2, b: s0.b.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:29:19
+   |
+LL |         let _s2 = S { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = S { a: 2, c: s0.c.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:37:19
+   |
+LL |         let _s2 = T { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = T { a: 2, b: s0.b.clone() };
+   |                           ~~~~~~~~~~~~~~~~~
+
+error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:42:19
+   |
+LL |         let _s2 = T { ..s0 };
+   |                   ^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = T { b: s0.b.clone(), ..s0 };
+   |                     ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
-  --> $DIR/borrowck-struct-update-with-dtor.rs:17:15
+  --> $DIR/borrowck-struct-update-with-dtor.rs:47:32
+   |
+LL |         let _s2 = T { a: 2, b: s0.b };
+   |                                ^^^^
+   |                                |
+   |                                cannot move out of here
+   |                                move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let _s2 = T { a: 2, b: s0.b.clone() };
+   |                                    ++++++++
+
+error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:52:19
+   |
+LL |         let _s2 = V { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = V { a: 2, b: s0.b.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:52:19
+   |
+LL |         let _s2 = V { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = V { a: 2, c: s0.c.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:58:19
+   |
+LL |         let _s2 = V { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |         let _s2 = V { a: 2, b: s0.b.clone(), ..s0 };
+   |                           +++++++++++++++++
+
+error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:58:19
+   |
+LL |         let _s2 = V { a: 2, ..s0 };
+   |                   ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   cannot move out of here
+   |                   move occurs because `s0.c` has type `Clonable`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
    |
-LL |     let _s2 = T{a: 2, ..s0};
-   |               ^^^^^^^^^^^^^
-   |               |
-   |               cannot move out of here
-   |               move occurs because `s0.mv` has type `Box<isize>`, which does not implement the `Copy` trait
+LL |         let _s2 = V { a: 2, c: s0.c.clone(), ..s0 };
+   |                           +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0509`.
diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr
index e6c3869f67a..598ecb53778 100644
--- a/tests/ui/borrowck/borrowck-unary-move.stderr
+++ b/tests/ui/borrowck/borrowck-unary-move.stderr
@@ -9,6 +9,12 @@ LL |     free(x);
    |          ^ move out of `x` occurs here
 LL |     *y
    |     -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = &*x;
+LL +     let y = x.clone();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.stderr b/tests/ui/borrowck/borrowck-unboxed-closures.stderr
index 3634676463c..a4513bd614e 100644
--- a/tests/ui/borrowck/borrowck-unboxed-closures.stderr
+++ b/tests/ui/borrowck/borrowck-unboxed-closures.stderr
@@ -29,15 +29,13 @@ LL |     f(1, 2);
 LL |     f(1, 2);
    |     ^ value used here after move
    |
-note: this value implements `FnOnce`, which causes it to be moved when called
-  --> $DIR/borrowck-unboxed-closures.rs:11:5
+note: `FnOnce` closures can only be called once
+  --> $DIR/borrowck-unboxed-closures.rs:10:8
    |
+LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `F` is made to be an `FnOnce` closure here
 LL |     f(1, 2);
-   |     ^
-help: consider further restricting this bound
-   |
-LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
-   |                                      ++++++
+   |     ------- this value implements `FnOnce`, which causes it to be moved when called
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.stderr b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
index 06bb419aa3b..c6d52a049d2 100644
--- a/tests/ui/borrowck/borrowck-uninit-after-item.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -9,8 +9,8 @@ LL |     baz(bar);
    |
 help: consider assigning a value
    |
-LL |     let bar = 0;
-   |             +++
+LL |     let bar = 42;
+   |             ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
index fdbb451bde4..aaa33f08ff5 100644
--- a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -8,8 +8,8 @@ LL |     x += 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:9:5
@@ -21,8 +21,8 @@ LL |     x -= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:12:5
@@ -34,8 +34,8 @@ LL |     x *= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:15:5
@@ -47,8 +47,8 @@ LL |     x /= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:18:5
@@ -60,8 +60,8 @@ LL |     x %= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:21:5
@@ -73,8 +73,8 @@ LL |     x ^= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:24:5
@@ -86,8 +86,8 @@ LL |     x &= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:27:5
@@ -99,8 +99,8 @@ LL |     x |= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:30:5
@@ -112,8 +112,8 @@ LL |     x <<= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:33:5
@@ -125,8 +125,8 @@ LL |     x >>= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
index 73fded7545c..d6759b8e1cf 100644
--- a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -8,8 +8,8 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&Box<i32> = todo!();
-   |                       +++++++++
+LL |     let x: &&Box<i32> = &&Box::new(42);
+   |                       ++++++++++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:11:14
@@ -21,7 +21,7 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&S<i32, i32> = todo!();
+LL |     let x: &&S<i32, i32> = &&value;
    |                          +++++++++
 
 error[E0381]: used binding `x` isn't initialized
@@ -34,8 +34,8 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&i32 = todo!();
-   |                  +++++++++
+LL |     let x: &&i32 = &&42;
+   |                  ++++++
 
 error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:18:5
diff --git a/tests/ui/borrowck/borrowck-uninit.stderr b/tests/ui/borrowck/borrowck-uninit.stderr
index 1e004baa143..9538baeafd1 100644
--- a/tests/ui/borrowck/borrowck-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-uninit.stderr
@@ -8,8 +8,8 @@ LL |     foo(x);
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `a` isn't initialized
   --> $DIR/borrowck-uninit.rs:14:32
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed
new file mode 100644
index 00000000000..947c7f5b744
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed
@@ -0,0 +1,11 @@
+//@ run-rustfix
+#[allow(unused_mut)]
+fn test() {
+    let w: &mut [isize] = &mut [];
+    w[5] = 0; //~ ERROR [E0381]
+
+    let mut w: &mut [isize] = &mut [];
+    w[5] = 0; //~ ERROR [E0381]
+}
+
+fn main() { test(); }
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
index d30b1de5cd0..a00fda60abb 100644
--- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
@@ -1,3 +1,5 @@
+//@ run-rustfix
+#[allow(unused_mut)]
 fn test() {
     let w: &mut [isize];
     w[5] = 0; //~ ERROR [E0381]
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
index 18e808f10d0..6ec4390ae8d 100644
--- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `w` isn't initialized
-  --> $DIR/borrowck-use-in-index-lvalue.rs:3:5
+  --> $DIR/borrowck-use-in-index-lvalue.rs:5:5
    |
 LL |     let w: &mut [isize];
    |         - binding declared here but left uninitialized
@@ -8,11 +8,11 @@ LL |     w[5] = 0;
    |
 help: consider assigning a value
    |
-LL |     let w: &mut [isize] = todo!();
+LL |     let w: &mut [isize] = &mut [];
    |                         +++++++++
 
 error[E0381]: used binding `w` isn't initialized
-  --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
+  --> $DIR/borrowck-use-in-index-lvalue.rs:8:5
    |
 LL |     let mut w: &mut [isize];
    |         ----- binding declared here but left uninitialized
@@ -21,7 +21,7 @@ LL |     w[5] = 0;
    |
 help: consider assigning a value
    |
-LL |     let mut w: &mut [isize] = todo!();
+LL |     let mut w: &mut [isize] = &mut [];
    |                             +++++++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed
new file mode 100644
index 00000000000..f6ea5f0b6b8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed
@@ -0,0 +1,12 @@
+// Variation on `borrowck-use-uninitialized-in-cast` in which we do a
+// trait cast from an uninitialized source. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables, dead_code)]
+
+trait Foo { fn dummy(&self) { } }
+impl Foo for i32 { }
+
+fn main() {
+    let x: &i32 = &42;
+    let y = x as *const dyn Foo; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
index 3ce72161814..a384fdbf950 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
@@ -1,5 +1,7 @@
 // Variation on `borrowck-use-uninitialized-in-cast` in which we do a
 // trait cast from an uninitialized source. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables, dead_code)]
 
 trait Foo { fn dummy(&self) { } }
 impl Foo for i32 { }
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
index dcbaa75333e..ef04979f1cd 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13
+  --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:11:13
    |
 LL |     let x: &i32;
    |         - binding declared here but left uninitialized
@@ -8,8 +8,8 @@ LL |     let y = x as *const dyn Foo;
    |
 help: consider assigning a value
    |
-LL |     let x: &i32 = todo!();
-   |                 +++++++++
+LL |     let x: &i32 = &42;
+   |                 +++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed
new file mode 100644
index 00000000000..9c72015d747
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed
@@ -0,0 +1,10 @@
+// Check that we detect unused values that are cast to other things.
+// The problem was specified to casting to `*`, as creating unsafe
+// pointers was not being fully checked. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables)]
+
+fn main() {
+    let x: &i32 = &42;
+    let y = x as *const i32; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
index a355a546dc6..290deb0f257 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
@@ -1,6 +1,8 @@
 // Check that we detect unused values that are cast to other things.
 // The problem was specified to casting to `*`, as creating unsafe
 // pointers was not being fully checked. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables)]
 
 fn main() {
     let x: &i32;
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
index 7ccf6a4c3fc..22a3b721179 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13
+  --> $DIR/borrowck-use-uninitialized-in-cast.rs:9:13
    |
 LL |     let x: &i32;
    |         - binding declared here but left uninitialized
@@ -8,8 +8,8 @@ LL |     let y = x as *const i32;
    |
 help: consider assigning a value
    |
-LL |     let x: &i32 = todo!();
-   |                 +++++++++
+LL |     let x: &i32 = &42;
+   |                 +++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
index 1bda7a49713..ec074d2cf1c 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
@@ -47,6 +47,7 @@ fn c() {
     //~| NOTE cannot move out of here
     //~| NOTE move occurs because
     //~| HELP consider borrowing here
+    //~| HELP consider cloning
 }
 
 fn d() {
@@ -66,6 +67,7 @@ fn d() {
     //~| NOTE cannot move out of here
     //~| NOTE move occurs because
     //~| HELP consider borrowing here
+    //~| HELP consider cloning
 }
 
 fn e() {
@@ -86,6 +88,7 @@ fn e() {
     //~| NOTE cannot move out of here
     //~| NOTE move occurs because
     //~| HELP consider borrowing here
+    //~| HELP consider cloning
 }
 
 fn main() {}
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
index 024cb006c26..fff997fd555 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -53,9 +53,13 @@ help: consider borrowing here
    |
 LL |     let a = &vec[0];
    |             +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = vec[0].clone();
+   |                   ++++++++
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:55:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:56:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -73,7 +77,7 @@ LL +         [
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:65:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:66:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -85,9 +89,13 @@ help: consider borrowing here
    |
 LL |     let a = &vec[0];
    |             +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = vec[0].clone();
+   |                   ++++++++
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:74:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:76:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -106,7 +114,7 @@ LL +         [_a, _b, _c] => {}
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:85:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:87:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -118,6 +126,10 @@ help: consider borrowing here
    |
 LL |     let a = &vec[0];
    |             +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = vec[0].clone();
+   |                   ++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index ee4fcadf55a..f0eaf4bac7d 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -52,6 +52,11 @@ LL |
 LL |     println!("{b:?}");
    |               ----- borrow later used here
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/clone-on-ref.rs:19:1
+   |
+LL | struct A;
+   | ^^^^^^^^
 help: consider annotating `A` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/borrowck/clone-span-on-try-operator.fixed b/tests/ui/borrowck/clone-span-on-try-operator.fixed
index 59253c98079..59a162e72c1 100644
--- a/tests/ui/borrowck/clone-span-on-try-operator.fixed
+++ b/tests/ui/borrowck/clone-span-on-try-operator.fixed
@@ -7,5 +7,5 @@ impl Foo {
 }
 fn main() {
     let foo = &Foo;
-    <Foo as Clone>::clone(&(*foo)).foo(); //~ ERROR cannot move out
+    <Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
 }
diff --git a/tests/ui/borrowck/clone-span-on-try-operator.stderr b/tests/ui/borrowck/clone-span-on-try-operator.stderr
index adf84e49a9f..c2c63f94943 100644
--- a/tests/ui/borrowck/clone-span-on-try-operator.stderr
+++ b/tests/ui/borrowck/clone-span-on-try-operator.stderr
@@ -15,6 +15,11 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |     <Foo as Clone>::clone(&(*foo)).foo();
    |     +++++++++++++++++++++++      +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     (*foo).foo();
+LL +     foo.clone().foo();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr
index 1f32ece3d3d..b4775496f4f 100644
--- a/tests/ui/borrowck/issue-101119.stderr
+++ b/tests/ui/borrowck/issue-101119.stderr
@@ -4,11 +4,25 @@ error[E0382]: use of moved value: `state`
 LL | fn fill_memory_blocks_mt(state: &mut State) {
    |                          ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         once(move || {
    |              ^^^^^^^ value moved into closure here, in previous iteration of loop
 LL |
 LL |             fill_segment(state);
    |                          ----- use occurs due to use in closure
+   |
+note: consider changing this parameter type in function `fill_segment` to borrow instead if owning the value isn't necessary
+  --> $DIR/issue-101119.rs:14:20
+   |
+LL | fn fill_segment(_: &mut State) {}
+   |    ------------    ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `State` implemented `Clone`, you could clone the value
+  --> $DIR/issue-101119.rs:1:1
+   |
+LL | struct State;
+   | ^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-103250.stderr b/tests/ui/borrowck/issue-103250.stderr
index b7ece5d971d..104bded5b0b 100644
--- a/tests/ui/borrowck/issue-103250.stderr
+++ b/tests/ui/borrowck/issue-103250.stderr
@@ -9,8 +9,8 @@ LL |         Err(last_error)
    |
 help: consider assigning a value
    |
-LL |         let mut last_error: Box<dyn std::error::Error> = todo!();
-   |                                                        +++++++++
+LL |         let mut last_error: Box<dyn std::error::Error> = Box::new(value);
+   |                                                        +++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
index 7a281e8aa30..94421c35c65 100644
--- a/tests/ui/borrowck/issue-103624.stderr
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -9,6 +9,12 @@ LL |         spawn_blocking(move || {
 LL |
 LL |             self.b;
    |             ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
+   |
+note: if `StructB` implemented `Clone`, you could clone the value
+  --> $DIR/issue-103624.rs:23:1
+   |
+LL | struct StructB {}
+   | ^^^^^^^^^^^^^^
 
 error[E0521]: borrowed data escapes outside of method
   --> $DIR/issue-103624.rs:14:9
diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
index ab42205d510..701f00d079d 100644
--- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
+++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
@@ -11,6 +11,11 @@ note: `Example::<E, FakeParam>::change` takes ownership of the receiver `self`,
    |
 LL |     unsafe fn change<NewFakeParam>(self) -> Example<E, NewFakeParam> {
    |                                    ^^^^
+note: if `Example<E, NoLifetime>` implemented `Clone`, you could clone the value
+  --> $DIR/issue-119915-bad-clone-suggestion.rs:3:1
+   |
+LL | struct Example<E, FakeParam>(PhantomData<(fn(E), fn(FakeParam))>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr
index 5ca0a7fb885..e2c3a9d5a26 100644
--- a/tests/ui/borrowck/issue-17718-static-move.stderr
+++ b/tests/ui/borrowck/issue-17718-static-move.stderr
@@ -4,6 +4,11 @@ error[E0507]: cannot move out of static item `FOO`
 LL |     let _a = FOO;
    |              ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
    |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/issue-17718-static-move.rs:1:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^
 help: consider borrowing here
    |
 LL |     let _a = &FOO;
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
index 97294afd3df..1da6f0bef02 100644
--- a/tests/ui/borrowck/issue-20801.stderr
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -19,6 +19,11 @@ error[E0507]: cannot move out of a mutable reference
 LL |     let a = unsafe { *mut_ref() };
    |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
    |
+note: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/issue-20801.rs:3:1
+   |
+LL | struct T(u8);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let a = unsafe { *mut_ref() };
@@ -31,6 +36,11 @@ error[E0507]: cannot move out of a shared reference
 LL |     let b = unsafe { *imm_ref() };
    |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
    |
+note: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/issue-20801.rs:3:1
+   |
+LL | struct T(u8);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let b = unsafe { *imm_ref() };
@@ -43,6 +53,11 @@ error[E0507]: cannot move out of a raw pointer
 LL |     let c = unsafe { *mut_ptr() };
    |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
    |
+note: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/issue-20801.rs:3:1
+   |
+LL | struct T(u8);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let c = unsafe { *mut_ptr() };
@@ -55,6 +70,11 @@ error[E0507]: cannot move out of a raw pointer
 LL |     let d = unsafe { *const_ptr() };
    |                      ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
    |
+note: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/issue-20801.rs:3:1
+   |
+LL | struct T(u8);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let d = unsafe { *const_ptr() };
diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr
index 58d1c8c0f73..216f8d49b1b 100644
--- a/tests/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:18:20
@@ -25,8 +25,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
index e19f37538c1..8705b8450fc 100644
--- a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
+++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -9,8 +9,8 @@ LL |         ref u if true => {}
    |
 help: consider assigning a value
    |
-LL |     let e: i32 = 0;
-   |                +++
+LL |     let e: i32 = 42;
+   |                ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index f032ea779dd..0e4a8d42f6e 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -22,6 +22,11 @@ error[E0507]: cannot move out of static item `settings_dir`
    |
 LL |     let settings_data = from_string(settings_dir);
    |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let settings_data = from_string(settings_dir.clone());
+   |                                                 ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
index a15909df07b..a0c7cac2add 100644
--- a/tests/ui/borrowck/issue-87456-point-to-closure.stderr
+++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
@@ -14,6 +14,10 @@ help: consider borrowing here
    |
 LL |         let _foo: String = &val;
    |                            +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let _foo: String = val.clone();
+   |                               ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr
index 0d5edadcb46..43f4e820857 100644
--- a/tests/ui/borrowck/move-error-in-promoted-2.stderr
+++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr
@@ -6,6 +6,12 @@ LL |     &([S][0],);
    |       |
    |       cannot move out of here
    |       move occurs because value has type `S`, which does not implement the `Copy` trait
+   |
+note: if `S` implemented `Clone`, you could clone the value
+  --> $DIR/move-error-in-promoted-2.rs:3:1
+   |
+LL | struct S;
+   | ^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/move-error-in-promoted.stderr b/tests/ui/borrowck/move-error-in-promoted.stderr
index 03c0297c5a9..8d42df24e27 100644
--- a/tests/ui/borrowck/move-error-in-promoted.stderr
+++ b/tests/ui/borrowck/move-error-in-promoted.stderr
@@ -6,6 +6,11 @@ LL |     let _ = S1(C[0]).clone();
    |                |
    |                cannot move out of here
    |                move occurs because value has type `S2`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _ = S1(C[0].clone()).clone();
+   |                    ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr
index 83f9e19aa0d..40b64398aef 100644
--- a/tests/ui/borrowck/move-error-snippets.stderr
+++ b/tests/ui/borrowck/move-error-snippets.stderr
@@ -9,6 +9,11 @@ LL |         let a = $c;
 LL | sss!();
    | ------ in this macro invocation
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-error-snippets.rs:9:1
+   |
+LL | struct A;
+   | ^^^^^^^^
    = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr
index 70078582713..c951ce8e3cd 100644
--- a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr
+++ b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr
@@ -3,24 +3,48 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference
    |
 LL |     *u.a
    |     ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *u.a
+LL +     u.a.clone()
+   |
 
 error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
   --> $DIR/move-from-union-field-issue-66500.rs:16:5
    |
 LL |     *u.b
    |     ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *u.b
+LL +     u.b.clone()
+   |
 
 error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
   --> $DIR/move-from-union-field-issue-66500.rs:20:5
    |
 LL |     *u.c
    |     ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *u.c
+LL +     u.c.clone()
+   |
 
 error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
   --> $DIR/move-from-union-field-issue-66500.rs:24:5
    |
 LL |     *u.d
    |     ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *u.d
+LL +     u.d.clone()
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
index 6619fb42c28..a4e70b50646 100644
--- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
+++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
@@ -3,12 +3,24 @@ error[E0507]: cannot move out of a shared reference
    |
 LL | static Y: usize = get(*&X);
    |                       ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/move-in-static-initializer-issue-38520.rs:5:1
+   |
+LL | struct Foo(usize);
+   | ^^^^^^^^^^
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/move-in-static-initializer-issue-38520.rs:13:22
    |
 LL | const Z: usize = get(*&X);
    |                      ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/move-in-static-initializer-issue-38520.rs:5:1
+   |
+LL | struct Foo(usize);
+   | ^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr
index 92acba640d7..4305539f1b6 100644
--- a/tests/ui/borrowck/suggest-assign-rvalue.stderr
+++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr
@@ -8,8 +8,8 @@ LL |     apple(chaenomeles);
    |
 help: consider assigning a value
    |
-LL |     let chaenomeles = 0;
-   |                     +++
+LL |     let chaenomeles = 42;
+   |                     ++++
 
 error[E0381]: used binding `my_float` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:23:30
@@ -22,8 +22,8 @@ LL |     println!("my_float: {}", my_float);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let my_float: f32 = 0.0;
-   |                       +++++
+LL |     let my_float: f32 = 3.14159;
+   |                       +++++++++
 
 error[E0381]: used binding `demo` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:26:28
@@ -50,8 +50,8 @@ LL |     println!("demo_no: {:?}", demo_no);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let demo_no: DemoNoDef = todo!();
-   |                            +++++++++
+LL |     let demo_no: DemoNoDef = value;
+   |                            +++++++
 
 error[E0381]: used binding `arr` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:34:27
@@ -64,7 +64,7 @@ LL |     println!("arr: {:?}", arr);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let arr: [i32; 5] = todo!();
+LL |     let arr: [i32; 5] = [42; 5];
    |                       +++++++++
 
 error[E0381]: used binding `foo` isn't initialized
@@ -106,8 +106,8 @@ LL |     println!("my_int: {}", *my_int);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let my_int: &i32 = todo!();
-   |                      +++++++++
+LL |     let my_int: &i32 = &42;
+   |                      +++++
 
 error[E0381]: used binding `hello` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:49:27
@@ -120,8 +120,8 @@ LL |     println!("hello: {}", hello);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let hello: &str = todo!();
-   |                     +++++++++
+LL |     let hello: &str = "";
+   |                     ++++
 
 error[E0381]: used binding `never` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:53:27
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.rs b/tests/ui/borrowck/trait-impl-argument-difference-ice.rs
new file mode 100644
index 00000000000..872507cc4de
--- /dev/null
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.rs
@@ -0,0 +1,25 @@
+// Issue https://github.com/rust-lang/rust/issues/123414
+trait MemoryUnit {
+    extern "C" fn read_word(&mut self) -> u8;
+    extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+    //~^ WARNING anonymous parameters are deprecated and will be removed in the next edition
+    //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+    //~| ERROR associated type `Assoc` not found for `Self`
+}
+
+struct ROM {}
+
+impl MemoryUnit for ROM {
+//~^ ERROR not all trait items implemented, missing: `read_word`
+    extern "C" fn read_dword(&'_ self) -> u16 {
+        //~^ ERROR method `read_dword` has a `&self` declaration in the impl, but not in the trait
+        let a16 = self.read_word() as u16;
+        //~^ ERROR cannot borrow `*self` as mutable, as it is behind a `&` reference
+        let b16 = self.read_word() as u16;
+        //~^ ERROR cannot borrow `*self` as mutable, as it is behind a `&` reference
+
+        (b16 << 8) | a16
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
new file mode 100644
index 00000000000..5c70eccfbd3
--- /dev/null
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
@@ -0,0 +1,60 @@
+warning: anonymous parameters are deprecated and will be removed in the next edition
+  --> $DIR/trait-impl-argument-difference-ice.rs:4:30
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                              ^^^^^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: Self::Assoc<'_>`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+   = note: `#[warn(anonymous_parameters)]` on by default
+
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/trait-impl-argument-difference-ice.rs:4:36
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                                    ^^^^^ associated type `Assoc` not found
+
+error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
+  --> $DIR/trait-impl-argument-difference-ice.rs:14:5
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |     ------------------------------------------------- trait method declared without `&self`
+...
+LL |     extern "C" fn read_dword(&'_ self) -> u16 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&self` used in impl
+
+error[E0046]: not all trait items implemented, missing: `read_word`
+  --> $DIR/trait-impl-argument-difference-ice.rs:12:1
+   |
+LL |     extern "C" fn read_word(&mut self) -> u8;
+   |     ----------------------------------------- `read_word` from trait
+...
+LL | impl MemoryUnit for ROM {
+   | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation
+
+error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference
+  --> $DIR/trait-impl-argument-difference-ice.rs:16:19
+   |
+LL |         let a16 = self.read_word() as u16;
+   |                   ^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
+   |
+LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
+   |                              ~~~~~~~~~~~~
+
+error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference
+  --> $DIR/trait-impl-argument-difference-ice.rs:18:19
+   |
+LL |         let b16 = self.read_word() as u16;
+   |                   ^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
+   |
+LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
+   |                              ~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0046, E0185, E0220, E0596.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
index 8add3a5f2b6..3b4f7c8465c 100644
--- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
@@ -9,7 +9,7 @@ fn call<F>(f: F) where F : Fn() {
 fn main() {
     let y = vec![format!("World")];
     call(|| {
-        <Vec<String> as Clone>::clone(&y).into_iter();
+        <Vec<String> as Clone>::clone(&y.clone()).into_iter();
         //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
     });
 }
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
index a2ff70255f5..177e9c8d248 100644
--- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -16,6 +16,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |         <Vec<String> as Clone>::clone(&y).into_iter();
    |         +++++++++++++++++++++++++++++++ +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         y.clone().into_iter();
+   |          ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr
index 8b8cea3fe84..53ff5f0107d 100644
--- a/tests/ui/box/leak-alloc.stderr
+++ b/tests/ui/box/leak-alloc.stderr
@@ -11,6 +11,12 @@ LL |     drop(alloc);
 LL |
 LL |     use_value(*theref)
    |               ------- borrow later used here
+   |
+note: if `Alloc` implemented `Clone`, you could clone the value
+  --> $DIR/leak-alloc.rs:8:1
+   |
+LL | struct Alloc {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/btreemap/btreemap_dropck.stderr b/tests/ui/btreemap/btreemap_dropck.stderr
index 805c2112bdc..873f8cf9a01 100644
--- a/tests/ui/btreemap/btreemap_dropck.stderr
+++ b/tests/ui/btreemap/btreemap_dropck.stderr
@@ -9,6 +9,12 @@ LL |     drop(s);
    |          ^ move out of `s` occurs here
 LL | }
    | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
+LL +     let _map = BTreeMap::from_iter([((), PrintOnDrop(s.clone()))]);
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/check-static-values-constraints.stderr
index dee1f2b1210..fe5f2a34272 100644
--- a/tests/ui/check-static-values-constraints.stderr
+++ b/tests/ui/check-static-values-constraints.stderr
@@ -160,6 +160,10 @@ help: consider borrowing here
    |
 LL |         &x
    |         +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         x.clone()
+   |          ++++++++
 
 error: aborting due to 17 previous errors
 
diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index 8a32f0d99e7..f8ed792e3c6 100644
--- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -79,8 +79,8 @@ LL |     let c1 = || match x { };
    |
 help: consider assigning a value
    |
-LL |     let x: u8 = 0;
-   |               +++
+LL |     let x: u8 = 42;
+   |               ++++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/closures/return-value-lifetime-error.fixed b/tests/ui/closures/return-value-lifetime-error.fixed
new file mode 100644
index 00000000000..bf1f7e4a6cf
--- /dev/null
+++ b/tests/ui/closures/return-value-lifetime-error.fixed
@@ -0,0 +1,16 @@
+//@ run-rustfix
+use std::collections::HashMap;
+
+fn main() {
+    let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3];
+
+    let mut counts = HashMap::new();
+    for num in vs {
+        let count = counts.entry(num).or_insert(0);
+        *count += 1;
+    }
+
+    let _ = counts.iter().max_by_key(|(_, v)| **v);
+    //~^ ERROR lifetime may not live long enough
+    //~| HELP dereference the return value
+}
diff --git a/tests/ui/closures/return-value-lifetime-error.rs b/tests/ui/closures/return-value-lifetime-error.rs
new file mode 100644
index 00000000000..411c91f413e
--- /dev/null
+++ b/tests/ui/closures/return-value-lifetime-error.rs
@@ -0,0 +1,16 @@
+//@ run-rustfix
+use std::collections::HashMap;
+
+fn main() {
+    let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3];
+
+    let mut counts = HashMap::new();
+    for num in vs {
+        let count = counts.entry(num).or_insert(0);
+        *count += 1;
+    }
+
+    let _ = counts.iter().max_by_key(|(_, v)| v);
+    //~^ ERROR lifetime may not live long enough
+    //~| HELP dereference the return value
+}
diff --git a/tests/ui/closures/return-value-lifetime-error.stderr b/tests/ui/closures/return-value-lifetime-error.stderr
new file mode 100644
index 00000000000..a0ad127db28
--- /dev/null
+++ b/tests/ui/closures/return-value-lifetime-error.stderr
@@ -0,0 +1,16 @@
+error: lifetime may not live long enough
+  --> $DIR/return-value-lifetime-error.rs:13:47
+   |
+LL |     let _ = counts.iter().max_by_key(|(_, v)| v);
+   |                                       ------- ^ returning this value requires that `'1` must outlive `'2`
+   |                                       |     |
+   |                                       |     return type of closure is &'2 &i32
+   |                                       has type `&'1 (&i32, &i32)`
+   |
+help: dereference the return value
+   |
+LL |     let _ = counts.iter().max_by_key(|(_, v)| **v);
+   |                                               ++
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed
new file mode 100644
index 00000000000..da48c62df21
--- /dev/null
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed
@@ -0,0 +1,6 @@
+//@ run-rustfix
+pub struct X<const N: usize = {
+    let s: &'static str = ""; s.len() //~ ERROR E0381
+}>;
+
+fn main() {}
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
index e64adacac9f..0d7d87100b7 100644
--- a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
@@ -1,4 +1,5 @@
-struct X<const N: usize = {
+//@ run-rustfix
+pub struct X<const N: usize = {
     let s: &'static str; s.len() //~ ERROR E0381
 }>;
 
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
index 4cea35f1c8e..83e7f88eda7 100644
--- a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `s` isn't initialized
-  --> $DIR/const-generic-default-wont-borrowck.rs:2:26
+  --> $DIR/const-generic-default-wont-borrowck.rs:3:26
    |
 LL |     let s: &'static str; s.len()
    |         -                ^ `*s` used here but it isn't initialized
@@ -8,8 +8,8 @@ LL |     let s: &'static str; s.len()
    |
 help: consider assigning a value
    |
-LL |     let s: &'static str = todo!(); s.len()
-   |                         +++++++++
+LL |     let s: &'static str = ""; s.len()
+   |                         ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/defaults/doesnt_infer.rs b/tests/ui/const-generics/defaults/doesnt_infer.rs
index 9c59e672d8e..e14c08fc148 100644
--- a/tests/ui/const-generics/defaults/doesnt_infer.rs
+++ b/tests/ui/const-generics/defaults/doesnt_infer.rs
@@ -9,5 +9,5 @@ impl<const N: u32> Foo<N> {
 fn main() {
     let foo = Foo::<1>::foo();
     let foo = Foo::foo();
-    //~^ error: type annotations needed for `Foo<N>`
+    //~^ ERROR type annotations needed for `Foo<_>`
 }
diff --git a/tests/ui/const-generics/defaults/doesnt_infer.stderr b/tests/ui/const-generics/defaults/doesnt_infer.stderr
index 65ee0ecfdc5..93d58603397 100644
--- a/tests/ui/const-generics/defaults/doesnt_infer.stderr
+++ b/tests/ui/const-generics/defaults/doesnt_infer.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Foo<N>`
+error[E0282]: type annotations needed for `Foo<_>`
   --> $DIR/doesnt_infer.rs:11:9
    |
 LL |     let foo = Foo::foo();
diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr
index 5b296a14869..5ee42c19dd3 100644
--- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr
+++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed for `Mask<_, N>`
+error[E0283]: type annotations needed for `Mask<_, _>`
   --> $DIR/issue-91614.rs:6:9
    |
 LL |     let y = Mask::<_, _>::splat(false);
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr
index f27d52a1437..5cda4681b5c 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr
@@ -18,7 +18,7 @@ help: try adding a `where` bound
 LL |     pub const fn new() -> Self where [(); Self::SIZE]: {
    |                                +++++++++++++++++++++++
 
-error[E0282]: type annotations needed for `ArrayHolder<X>`
+error[E0282]: type annotations needed for `ArrayHolder<_>`
   --> $DIR/issue-62504.rs:26:9
    |
 LL |     let mut array = ArrayHolder::new();
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr
index 1664669eee0..beb159779ff 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr
@@ -22,7 +22,7 @@ note: tuple struct defined here
 LL | struct ArrayHolder<const X: usize>([u32; X]);
    |        ^^^^^^^^^^^
 
-error[E0282]: type annotations needed for `ArrayHolder<X>`
+error[E0282]: type annotations needed for `ArrayHolder<_>`
   --> $DIR/issue-62504.rs:26:9
    |
 LL |     let mut array = ArrayHolder::new();
diff --git a/tests/ui/consts/const_fn_unsize.rs b/tests/ui/consts/const_fn_unsize.rs
index f96a6088fd3..15d717e7e12 100644
--- a/tests/ui/consts/const_fn_unsize.rs
+++ b/tests/ui/consts/const_fn_unsize.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-#![feature(slice_ptr_len)]
 
 use std::ptr::NonNull;
 
diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr
index 5a38d023d6f..ccaed03b4c1 100644
--- a/tests/ui/consts/issue-78655.stderr
+++ b/tests/ui/consts/issue-78655.stderr
@@ -8,8 +8,8 @@ LL |     &x
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr
index c538061b365..2de4ee4eabd 100644
--- a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr
@@ -8,6 +8,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -19,6 +23,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -30,6 +38,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -41,6 +53,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -52,6 +68,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -63,6 +83,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -74,6 +98,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -85,6 +113,10 @@ LL | struct StructA(String);
    |
    = note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@@ -96,78 +128,142 @@ LL | struct StructA(String);
    |
    = note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL | struct StructA(String.clone());
+   |                      ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:28:9
    |
 LL |         self.0
    |         ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         self.0.clone()
+   |               ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:38:20
    |
 LL |         let x = &{ self.0 };
    |                    ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = &{ self.0.clone() };
+   |                          ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:45:12
    |
 LL |         ({ self.0 }) == ({ other.0 })
    |            ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         ({ self.0.clone() }) == ({ other.0 })
+   |                  ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:45:28
    |
 LL |         ({ self.0 }) == ({ other.0 })
    |                            ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         ({ self.0 }) == ({ other.0.clone() })
+   |                                   ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:53:36
    |
 LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
    |                                    ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 })
+   |                                          ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:53:49
    |
 LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
    |                                                 ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() })
+   |                                                        ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:68:20
    |
 LL |         let x = &{ self.0 };
    |                    ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = &{ self.0.clone() };
+   |                          ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:75:12
    |
 LL |         ({ self.0 }) == ({ other.0 })
    |            ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         ({ self.0.clone() }) == ({ other.0 })
+   |                  ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:75:28
    |
 LL |         ({ self.0 }) == ({ other.0 })
    |                            ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         ({ self.0 }) == ({ other.0.clone() })
+   |                                   ++++++++
 
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:83:36
    |
 LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
    |                                    ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 })
+   |                                          ++++++++
 
 error[E0507]: cannot move out of `other` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:83:49
    |
 LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
    |                                                 ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() })
+   |                                                        ++++++++
 
 error[E0507]: cannot move out of `arg` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed-move-errors.rs:92:5
    |
 LL |     arg.0
    |     ^^^^^ move occurs because `arg.0` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     arg.0.clone()
+   |          ++++++++
 
 error: aborting due to 21 previous errors
 
diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr
index 151be6901b0..26ac532263f 100644
--- a/tests/ui/derives/deriving-with-repr-packed.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed.stderr
@@ -36,6 +36,11 @@ LL | #[repr(packed)]
 LL | struct X(Y);
    |          ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait
    |
+note: if `Y` implemented `Clone`, you could clone the value
+  --> $DIR/deriving-with-repr-packed.rs:16:1
+   |
+LL | struct Y(usize);
+   | ^^^^^^^^
    = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/drop/repeat-drop-2.stderr b/tests/ui/drop/repeat-drop-2.stderr
index 009a2057212..cea7baf6976 100644
--- a/tests/ui/drop/repeat-drop-2.stderr
+++ b/tests/ui/drop/repeat-drop-2.stderr
@@ -32,8 +32,8 @@ LL |     let _ = [x; 0];
    |
 help: consider assigning a value
    |
-LL |     let x: u8 = 0;
-   |               +++
+LL |     let x: u8 = 42;
+   |               ++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/dropck/drop-with-active-borrows-1.stderr b/tests/ui/dropck/drop-with-active-borrows-1.stderr
index 229514c6fee..7d1633267f0 100644
--- a/tests/ui/dropck/drop-with-active-borrows-1.stderr
+++ b/tests/ui/dropck/drop-with-active-borrows-1.stderr
@@ -9,6 +9,11 @@ LL |     drop(a);
    |          ^ move out of `a` occurs here
 LL |     for s in &b {
    |              -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let b: Vec<&str> = a.clone().lines().collect();
+   |                         ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0449.fixed b/tests/ui/error-codes/E0449.fixed
new file mode 100644
index 00000000000..c7b4566303d
--- /dev/null
+++ b/tests/ui/error-codes/E0449.fixed
@@ -0,0 +1,18 @@
+//@ run-rustfix
+
+#![allow(warnings)]
+
+struct Bar;
+
+trait Foo {
+    fn foo();
+}
+
+ impl Bar {} //~ ERROR E0449
+
+ impl Foo for Bar { //~ ERROR E0449
+     fn foo() {} //~ ERROR E0449
+}
+
+fn main() {
+}
diff --git a/tests/ui/error-codes/E0449.rs b/tests/ui/error-codes/E0449.rs
index eba0d479e97..32d9b35169c 100644
--- a/tests/ui/error-codes/E0449.rs
+++ b/tests/ui/error-codes/E0449.rs
@@ -1,3 +1,7 @@
+//@ run-rustfix
+
+#![allow(warnings)]
+
 struct Bar;
 
 trait Foo {
diff --git a/tests/ui/error-codes/E0449.stderr b/tests/ui/error-codes/E0449.stderr
index cf41bcce8c2..c6a98269a19 100644
--- a/tests/ui/error-codes/E0449.stderr
+++ b/tests/ui/error-codes/E0449.stderr
@@ -1,24 +1,24 @@
 error[E0449]: visibility qualifiers are not permitted here
-  --> $DIR/E0449.rs:7:1
+  --> $DIR/E0449.rs:11:1
    |
 LL | pub impl Bar {}
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual impl items instead
 
 error[E0449]: visibility qualifiers are not permitted here
-  --> $DIR/E0449.rs:9:1
+  --> $DIR/E0449.rs:13:1
    |
 LL | pub impl Foo for Bar {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
 error[E0449]: visibility qualifiers are not permitted here
-  --> $DIR/E0449.rs:10:5
+  --> $DIR/E0449.rs:14:5
    |
 LL |     pub fn foo() {}
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr
index c8a48961cb3..900cb706bd9 100644
--- a/tests/ui/error-codes/E0504.stderr
+++ b/tests/ui/error-codes/E0504.stderr
@@ -13,6 +13,12 @@ LL |         println!("child function: {}", fancy_num.num);
 ...
 LL |     println!("main function: {}", fancy_ref.num);
    |                                   ------------- borrow later used here
+   |
+note: if `FancyNum` implemented `Clone`, you could clone the value
+  --> $DIR/E0504.rs:1:1
+   |
+LL | struct FancyNum {
+   | ^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr
index 250680d2c1c..ce01298a70d 100644
--- a/tests/ui/error-codes/E0505.stderr
+++ b/tests/ui/error-codes/E0505.stderr
@@ -10,6 +10,12 @@ LL |         eat(x);
    |             ^ move out of `x` occurs here
 LL |         _ref_to_val.use_ref();
    |         ----------- borrow later used here
+   |
+note: if `Value` implemented `Clone`, you could clone the value
+  --> $DIR/E0505.rs:1:1
+   |
+LL | struct Value {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr
index 767fedfccbf..60a4daa9d38 100644
--- a/tests/ui/error-codes/E0507.stderr
+++ b/tests/ui/error-codes/E0507.stderr
@@ -11,6 +11,11 @@ note: `TheDarkKnight::nothing_is_true` takes ownership of the receiver `self`, w
    |
 LL |     fn nothing_is_true(self) {}
    |                        ^^^^
+note: if `TheDarkKnight` implemented `Clone`, you could clone the value
+  --> $DIR/E0507.rs:3:1
+   |
+LL | struct TheDarkKnight;
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr
index 1153b1d09c7..96d3bcb67a5 100644
--- a/tests/ui/error-codes/E0508-fail.stderr
+++ b/tests/ui/error-codes/E0508-fail.stderr
@@ -7,6 +7,11 @@ LL |     let _value = array[0];
    |                  cannot move out of here
    |                  move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
    |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/E0508-fail.rs:1:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 help: consider borrowing here
    |
 LL |     let _value = &array[0];
diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr
index 4c864e24144..c1b622e2432 100644
--- a/tests/ui/error-codes/E0508.stderr
+++ b/tests/ui/error-codes/E0508.stderr
@@ -7,6 +7,11 @@ LL |     let _value = array[0];
    |                  cannot move out of here
    |                  move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
    |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/E0508.rs:1:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 help: consider borrowing here
    |
 LL |     let _value = &array[0];
diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr
index 59843a5491a..75c372d0440 100644
--- a/tests/ui/error-codes/E0509.stderr
+++ b/tests/ui/error-codes/E0509.stderr
@@ -7,6 +7,11 @@ LL |     let fancy_field = drop_struct.fancy;
    |                       cannot move out of here
    |                       move occurs because `drop_struct.fancy` has type `FancyNum`, which does not implement the `Copy` trait
    |
+note: if `FancyNum` implemented `Clone`, you could clone the value
+  --> $DIR/E0509.rs:1:1
+   |
+LL | struct FancyNum {
+   | ^^^^^^^^^^^^^^^
 help: consider borrowing here
    |
 LL |     let fancy_field = &drop_struct.fancy;
diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr
index aa377553c50..bebf575d9a7 100644
--- a/tests/ui/fmt/send-sync.stderr
+++ b/tests/ui/fmt/send-sync.stderr
@@ -8,6 +8,8 @@ LL |     send(format_args!("{:?}", c));
    |
    = help: within `[core::fmt::rt::Argument<'_>]`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Send`
    = note: required because it appears within the type `&core::fmt::rt::Opaque`
+note: required because it appears within the type `core::fmt::rt::ArgumentType<'_>`
+  --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
 note: required because it appears within the type `core::fmt::rt::Argument<'_>`
   --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
    = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]`
@@ -30,6 +32,8 @@ LL |     sync(format_args!("{:?}", c));
    |
    = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Sync`
    = note: required because it appears within the type `&core::fmt::rt::Opaque`
+note: required because it appears within the type `core::fmt::rt::ArgumentType<'_>`
+  --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
 note: required because it appears within the type `core::fmt::rt::Argument<'_>`
   --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
    = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]`
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
index 3be630e2b23..b8ec2e3b7e7 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
@@ -10,6 +10,12 @@ LL |     drop(x);
 LL |
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = f(&x, ());
+LL +     let y = f(x.clone(), ());
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
index bf6d77b6269..382ab8636a2 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -27,6 +27,12 @@ LL |     drop(x);
    |          ^ move out of `x` occurs here
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = f(&x, ());
+LL +     let y = f(x.clone(), ());
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
index c2a8fa741ca..ce97d8527e8 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
@@ -10,6 +10,12 @@ LL |     drop(x);
 LL |
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = f(&x, ());
+LL +     let y = f(x.clone(), ());
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr b/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr
index 16808f29dac..d167a60dad3 100644
--- a/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr
+++ b/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr
@@ -6,6 +6,11 @@ LL |     let _b = A { y: Arc::new(3), ..a };
    |              |
    |              cannot move out of here
    |              move occurs because `a.x` has type `Arc<isize>`, which does not implement the `Copy` trait
+   |
+help: clone the value from the field instead of using the functional record update syntax
+   |
+LL |     let _b = A { y: Arc::new(3), x: a.x.clone() };
+   |                                ~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-const-items/inference-failure.stderr b/tests/ui/generic-const-items/inference-failure.stderr
index 10ecd83ec53..594743a47f4 100644
--- a/tests/ui/generic-const-items/inference-failure.stderr
+++ b/tests/ui/generic-const-items/inference-failure.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Option<T>`
+error[E0282]: type annotations needed for `Option<_>`
   --> $DIR/inference-failure.rs:8:9
    |
 LL |     let _ = NONE;
diff --git a/tests/ui/generic-const-items/parameter-defaults.stderr b/tests/ui/generic-const-items/parameter-defaults.stderr
index b8220af5d0e..13562c98f6d 100644
--- a/tests/ui/generic-const-items/parameter-defaults.stderr
+++ b/tests/ui/generic-const-items/parameter-defaults.stderr
@@ -4,7 +4,7 @@ error: defaults for type parameters are only allowed in `struct`, `enum`, `type`
 LL | const NONE<T = ()>: Option<T> = None::<T>;
    |            ^^^^^^
 
-error[E0282]: type annotations needed for `Option<T>`
+error[E0282]: type annotations needed for `Option<_>`
   --> $DIR/parameter-defaults.rs:13:9
    |
 LL |     let _ = NONE;
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
index 6832f21f25e..0d2aae689f0 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
@@ -46,10 +46,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let ...$e; { todo!() }
-   |             ++            +++++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
index cb9e48e70e3..9ba0e09e154 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
@@ -67,10 +67,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let $e...; { todo!() }
-   |             ++            +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:17
@@ -85,10 +81,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let $e..=; { todo!() }
-   |             ++            +++++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/imports/redundant-import-extern-prelude.rs b/tests/ui/imports/redundant-import-extern-prelude.rs
new file mode 100644
index 00000000000..f1de06417aa
--- /dev/null
+++ b/tests/ui/imports/redundant-import-extern-prelude.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+// Check that we detect imports that are redundant due to the extern prelude
+// and that we emit a reasonable diagnostic.
+// issue: rust-lang/rust#121915
+
+// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>.
+
+//@ compile-flags: --extern aux_issue_121915 --edition 2018
+//@ aux-build: aux-issue-121915.rs
+
+#[deny(unused_imports)]
+fn main() {
+    use aux_issue_121915;
+    //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly
+    aux_issue_121915::item();
+}
diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.rs b/tests/ui/imports/redundant-import-issue-121915-2015.rs
index d41d190bb58..be3b8209ada 100644
--- a/tests/ui/imports/redundant-import-issue-121915-2015.rs
+++ b/tests/ui/imports/redundant-import-issue-121915-2015.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 //@ compile-flags: --extern aux_issue_121915 --edition 2015
 //@ aux-build: aux-issue-121915.rs
 
@@ -6,6 +7,6 @@ extern crate aux_issue_121915;
 #[deny(unused_imports)]
 fn main() {
     use aux_issue_121915;
-    //~^ ERROR the item `aux_issue_121915` is imported redundantly
+    //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly
     aux_issue_121915::item();
 }
diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.stderr b/tests/ui/imports/redundant-import-issue-121915-2015.stderr
deleted file mode 100644
index 174ed4fb96b..00000000000
--- a/tests/ui/imports/redundant-import-issue-121915-2015.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: the item `aux_issue_121915` is imported redundantly
-  --> $DIR/redundant-import-issue-121915-2015.rs:8:9
-   |
-LL | extern crate aux_issue_121915;
-   | ------------------------------ the item `aux_issue_121915` is already imported here
-...
-LL |     use aux_issue_121915;
-   |         ^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/redundant-import-issue-121915-2015.rs:6:8
-   |
-LL | #[deny(unused_imports)]
-   |        ^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/imports/redundant-import-issue-121915.rs b/tests/ui/imports/redundant-import-issue-121915.rs
deleted file mode 100644
index 237acc4af25..00000000000
--- a/tests/ui/imports/redundant-import-issue-121915.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ compile-flags: --extern aux_issue_121915 --edition 2018
-//@ aux-build: aux-issue-121915.rs
-
-#[deny(unused_imports)]
-fn main() {
-    use aux_issue_121915;
-    //~^ ERROR the item `aux_issue_121915` is imported redundantly
-    aux_issue_121915::item();
-}
diff --git a/tests/ui/imports/redundant-import-issue-121915.stderr b/tests/ui/imports/redundant-import-issue-121915.stderr
deleted file mode 100644
index 0047d7c3420..00000000000
--- a/tests/ui/imports/redundant-import-issue-121915.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: the item `aux_issue_121915` is imported redundantly
-  --> $DIR/redundant-import-issue-121915.rs:6:9
-   |
-LL |     use aux_issue_121915;
-   |         ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by prelude
-   |
-note: the lint level is defined here
-  --> $DIR/redundant-import-issue-121915.rs:4:8
-   |
-LL | #[deny(unused_imports)]
-   |        ^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/imports/redundant-import-lang-prelude-attr.rs b/tests/ui/imports/redundant-import-lang-prelude-attr.rs
new file mode 100644
index 00000000000..59cd570f44c
--- /dev/null
+++ b/tests/ui/imports/redundant-import-lang-prelude-attr.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+// Check that we detect imports (of built-in attributes) that are redundant due to
+// the language prelude and that we emit a reasonable diagnostic.
+
+// Note that we use the term "extern prelude" in the label even though "language prelude"
+// would be more correct. However, it's not worth special-casing this.
+
+// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>.
+
+//@ edition: 2018
+
+#![deny(unused_imports)]
+
+use allow; //FIXME(unused_imports): ~ ERROR the item `allow` is imported redundantly
+
+#[allow(unused)]
+fn main() {}
diff --git a/tests/ui/imports/redundant-import-lang-prelude.rs b/tests/ui/imports/redundant-import-lang-prelude.rs
new file mode 100644
index 00000000000..53d3b709963
--- /dev/null
+++ b/tests/ui/imports/redundant-import-lang-prelude.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+// Check that we detect imports that are redundant due to the language prelude
+// and that we emit a reasonable diagnostic.
+
+// Note that we use the term "extern prelude" in the label even though "language prelude"
+// would be more correct. However, it's not worth special-casing this.
+
+// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>.
+
+#![deny(unused_imports)]
+
+use std::primitive::u8;
+//FIXME(unused_imports): ~^ ERROR the item `u8` is imported redundantly
+
+const _: u8 = 0;
+
+fn main() {}
diff --git a/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs b/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs
new file mode 100644
index 00000000000..4a79cb2c208
--- /dev/null
+++ b/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs
@@ -0,0 +1,23 @@
+// This test demonstrates that we currently don't make an effort to detect
+// imports made redundant by the `#[macro_use]` prelude.
+// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>.
+
+//@ check-pass
+//@ aux-build:two_macros.rs
+#![deny(unused_imports)]
+
+#[macro_use]
+extern crate two_macros;
+
+// This import is actually redundant due to the `#[macro_use]` above.
+use two_macros::n;
+
+// We intentionally reference two items from the `#[macro_use]`'d crate because
+// if we were to reference only item `n`, we would flag the `#[macro_use]`
+// attribute as redundant which would be correct of course.
+// That's interesting on its own -- we prefer "blaming" the `#[macro_use]`
+// over the import (here, `use two_macros::n`) when it comes to redundancy.
+n!();
+m!();
+
+fn main() {}
diff --git a/tests/ui/imports/suggest-remove-issue-121315.rs b/tests/ui/imports/suggest-remove-issue-121315.rs
index 63533480ec1..2bb82833a5b 100644
--- a/tests/ui/imports/suggest-remove-issue-121315.rs
+++ b/tests/ui/imports/suggest-remove-issue-121315.rs
@@ -1,19 +1,20 @@
 //@ compile-flags: --edition 2021
+
 #![deny(unused_imports)]
 #![allow(dead_code)]
 
 fn test0() {
     // Test remove FlatUnused
     use std::convert::TryFrom;
-    //~^ ERROR the item `TryFrom` is imported redundantly
+    //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly
     let _ = u32::try_from(5i32);
 }
 
 fn test1() {
     // FIXME(yukang) Test remove NestedFullUnused
     use std::convert::{TryFrom, TryInto};
-    //~^ ERROR the item `TryFrom` is imported redundantly
-    //~| ERROR the item `TryInto` is imported redundantly
+    //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly
+    //FIXME(unused_imports): ~| ERROR the item `TryInto` is imported redundantly
 
     let _ = u32::try_from(5i32);
     let _a: i32 = u32::try_into(5u32).unwrap();
@@ -23,7 +24,7 @@ fn test2() {
     // FIXME(yukang): Test remove both redundant and unused
     use std::convert::{AsMut, Into};
     //~^ ERROR unused import: `AsMut`
-    //~| ERROR the item `Into` is imported redundantly
+    //FIXME(unused_imports): ~| ERROR the item `Into` is imported redundantly
 
     let _a: u32 = (5u8).into();
 }
diff --git a/tests/ui/imports/suggest-remove-issue-121315.stderr b/tests/ui/imports/suggest-remove-issue-121315.stderr
index dbd742f6c78..5701514e1bd 100644
--- a/tests/ui/imports/suggest-remove-issue-121315.stderr
+++ b/tests/ui/imports/suggest-remove-issue-121315.stderr
@@ -1,56 +1,20 @@
-error: the item `TryFrom` is imported redundantly
-  --> $DIR/suggest-remove-issue-121315.rs:7:9
-   |
-LL |     use std::convert::TryFrom;
-   |         ^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `TryFrom` is already defined here
-   |
-note: the lint level is defined here
-  --> $DIR/suggest-remove-issue-121315.rs:2:9
-   |
-LL | #![deny(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-error: the item `TryFrom` is imported redundantly
-  --> $DIR/suggest-remove-issue-121315.rs:14:24
-   |
-LL |     use std::convert::{TryFrom, TryInto};
-   |                        ^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `TryFrom` is already defined here
-
-error: the item `TryInto` is imported redundantly
-  --> $DIR/suggest-remove-issue-121315.rs:14:33
-   |
-LL |     use std::convert::{TryFrom, TryInto};
-   |                                 ^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `TryInto` is already defined here
-
 error: unused import: `AsMut`
-  --> $DIR/suggest-remove-issue-121315.rs:24:24
+  --> $DIR/suggest-remove-issue-121315.rs:25:24
    |
 LL |     use std::convert::{AsMut, Into};
    |                        ^^^^^
-
-error: the item `Into` is imported redundantly
-  --> $DIR/suggest-remove-issue-121315.rs:24:31
    |
-LL |     use std::convert::{AsMut, Into};
-   |                               ^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+note: the lint level is defined here
+  --> $DIR/suggest-remove-issue-121315.rs:3:9
    |
-   = note: the item `Into` is already defined here
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
 
 error: unused import: `From`
-  --> $DIR/suggest-remove-issue-121315.rs:33:24
+  --> $DIR/suggest-remove-issue-121315.rs:34:24
    |
 LL |     use std::convert::{From, Infallible};
    |                        ^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/include-macros/mismatched-types.stderr b/tests/ui/include-macros/mismatched-types.stderr
index 4f2880e2f5d..9bc0e64464e 100644
--- a/tests/ui/include-macros/mismatched-types.stderr
+++ b/tests/ui/include-macros/mismatched-types.stderr
@@ -1,8 +1,11 @@
 error[E0308]: mismatched types
-  --> $DIR/mismatched-types.rs:2:20
+  --> $DIR/file.txt:0:1
+   |
+   |
+  ::: $DIR/mismatched-types.rs:2:12
    |
 LL |     let b: &[u8] = include_str!("file.txt");
-   |            -----   ^^^^^^^^^^^^^^^^^^^^^^^^ expected `&[u8]`, found `&str`
+   |            -----   ------------------------ in this macro invocation
    |            |
    |            expected due to this
    |
diff --git a/tests/ui/inference/cannot-infer-closure-circular.rs b/tests/ui/inference/cannot-infer-closure-circular.rs
index affb481496d..1b41171e74a 100644
--- a/tests/ui/inference/cannot-infer-closure-circular.rs
+++ b/tests/ui/inference/cannot-infer-closure-circular.rs
@@ -4,7 +4,7 @@ fn main() {
     // error handles this gracefully, and in particular doesn't generate an extra
     // note about the `?` operator in the closure body, which isn't relevant to
     // the inference.
-    let x = |r| { //~ ERROR type annotations needed for `Result<(), E>`
+    let x = |r| { //~ ERROR type annotations needed for `Result<(), _>`
         let v = r?;
         Ok(v)
     };
diff --git a/tests/ui/inference/cannot-infer-closure-circular.stderr b/tests/ui/inference/cannot-infer-closure-circular.stderr
index e3cf0cca837..a16e832f8ef 100644
--- a/tests/ui/inference/cannot-infer-closure-circular.stderr
+++ b/tests/ui/inference/cannot-infer-closure-circular.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Result<(), E>`
+error[E0282]: type annotations needed for `Result<(), _>`
   --> $DIR/cannot-infer-closure-circular.rs:7:14
    |
 LL |     let x = |r| {
diff --git a/tests/ui/inference/erase-type-params-in-label.stderr b/tests/ui/inference/erase-type-params-in-label.stderr
index 546e679f2d0..4e9a74c1e40 100644
--- a/tests/ui/inference/erase-type-params-in-label.stderr
+++ b/tests/ui/inference/erase-type-params-in-label.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
+error[E0283]: type annotations needed for `Foo<i32, &str, _, _>`
   --> $DIR/erase-type-params-in-label.rs:2:9
    |
 LL |     let foo = foo(1, "");
@@ -15,7 +15,7 @@ help: consider giving `foo` an explicit type, where the type for type parameter
 LL |     let foo: Foo<i32, &str, W, Z> = foo(1, "");
    |            ++++++++++++++++++++++
 
-error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
+error[E0283]: type annotations needed for `Bar<i32, &str, _>`
   --> $DIR/erase-type-params-in-label.rs:5:9
    |
 LL |     let bar = bar(1, "");
diff --git a/tests/ui/inference/issue-104649.stderr b/tests/ui/inference/issue-104649.stderr
index afece960914..391ed16f349 100644
--- a/tests/ui/inference/issue-104649.stderr
+++ b/tests/ui/inference/issue-104649.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `A<std::result::Result<std::result::Result<(), E>, Error>>`
+error[E0282]: type annotations needed for `A<std::result::Result<std::result::Result<(), _>, Error>>`
   --> $DIR/issue-104649.rs:24:9
    |
 LL |     let a = A(Result::Ok(Result::Ok(())));
diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr
index 6c93241ea07..6391672f861 100644
--- a/tests/ui/inference/issue-72690.stderr
+++ b/tests/ui/inference/issue-72690.stderr
@@ -50,7 +50,7 @@ help: try using a fully qualified path to specify the expected types
 LL |     |x| String::from(<str as AsRef<T>>::as_ref("x"));
    |                      ++++++++++++++++++++++++++   ~
 
-error[E0283]: type annotations needed for `&T`
+error[E0283]: type annotations needed for `&_`
   --> $DIR/issue-72690.rs:17:9
    |
 LL |     let _ = "x".as_ref();
diff --git a/tests/ui/inference/issue-83606.rs b/tests/ui/inference/issue-83606.rs
index c387046e910..4454b5e60f0 100644
--- a/tests/ui/inference/issue-83606.rs
+++ b/tests/ui/inference/issue-83606.rs
@@ -6,5 +6,5 @@ fn foo<const N: usize>(_: impl std::fmt::Display) -> [usize; N] {
 
 fn main() {
     let _ = foo("foo");
-    //~^ ERROR: type annotations needed for `[usize; N]`
+    //~^ ERROR type annotations needed for `[usize; _]`
 }
diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr
index 00de4029e42..8e6ff6d568d 100644
--- a/tests/ui/inference/issue-83606.stderr
+++ b/tests/ui/inference/issue-83606.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `[usize; N]`
+error[E0282]: type annotations needed for `[usize; _]`
   --> $DIR/issue-83606.rs:8:9
    |
 LL |     let _ = foo("foo");
diff --git a/tests/ui/inference/untyped-primitives.rs b/tests/ui/inference/untyped-primitives.rs
new file mode 100644
index 00000000000..8515ca79903
--- /dev/null
+++ b/tests/ui/inference/untyped-primitives.rs
@@ -0,0 +1,9 @@
+//@ check-pass
+// issue: rust-lang/rust#123824
+// This test is a sanity check and does not enforce any stable API, so may be
+// removed at a future point.
+
+fn main() {
+    let x = f32::from(3.14);
+    let y = f64::from(3.14);
+}
diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr
index 161fce4b031..d4a4647f6a1 100644
--- a/tests/ui/issues/issue-11771.stderr
+++ b/tests/ui/issues/issue-11771.stderr
@@ -6,15 +6,15 @@ LL |     1 +
    |
    = help: the trait `Add<()>` is not implemented for `{integer}`
    = help: the following other types implement trait `Add<Rhs>`:
+             <&'a f128 as Add<f128>>
+             <&'a f16 as Add<f16>>
              <&'a f32 as Add<f32>>
              <&'a f64 as Add<f64>>
              <&'a i128 as Add<i128>>
              <&'a i16 as Add<i16>>
              <&'a i32 as Add<i32>>
              <&'a i64 as Add<i64>>
-             <&'a i8 as Add<i8>>
-             <&'a isize as Add<isize>>
-           and 48 others
+           and 56 others
 
 error[E0277]: cannot add `()` to `{integer}`
   --> $DIR/issue-11771.rs:8:7
@@ -24,15 +24,15 @@ LL |     1 +
    |
    = help: the trait `Add<()>` is not implemented for `{integer}`
    = help: the following other types implement trait `Add<Rhs>`:
+             <&'a f128 as Add<f128>>
+             <&'a f16 as Add<f16>>
              <&'a f32 as Add<f32>>
              <&'a f64 as Add<f64>>
              <&'a i128 as Add<i128>>
              <&'a i16 as Add<i16>>
              <&'a i32 as Add<i32>>
              <&'a i64 as Add<i64>>
-             <&'a i8 as Add<i8>>
-             <&'a isize as Add<isize>>
-           and 48 others
+           and 56 others
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-12187-1.stderr b/tests/ui/issues/issue-12187-1.stderr
index 93dc1df8f63..704854fe585 100644
--- a/tests/ui/issues/issue-12187-1.stderr
+++ b/tests/ui/issues/issue-12187-1.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `&T`
+error[E0282]: type annotations needed for `&_`
   --> $DIR/issue-12187-1.rs:6:9
    |
 LL |     let &v = new();
diff --git a/tests/ui/issues/issue-12187-2.stderr b/tests/ui/issues/issue-12187-2.stderr
index e9ba52ff4fd..eeef63a1d0b 100644
--- a/tests/ui/issues/issue-12187-2.stderr
+++ b/tests/ui/issues/issue-12187-2.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `&T`
+error[E0282]: type annotations needed for `&_`
   --> $DIR/issue-12187-2.rs:6:9
    |
 LL |     let &v = new();
diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr
index 77aa201b335..988db0fb1fc 100644
--- a/tests/ui/issues/issue-17385.stderr
+++ b/tests/ui/issues/issue-17385.stderr
@@ -7,6 +7,12 @@ LL |     drop(foo);
    |          --- value moved here
 LL |     match foo {
    |     ^^^^^^^^^ value used here after move
+   |
+note: if `X` implemented `Clone`, you could clone the value
+  --> $DIR/issue-17385.rs:1:1
+   |
+LL | struct X(isize);
+   | ^^^^^^^^
 
 error[E0382]: use of moved value: `e`
   --> $DIR/issue-17385.rs:25:11
@@ -17,6 +23,12 @@ LL |     drop(e);
    |          - value moved here
 LL |     match e {
    |           ^ value used here after move
+   |
+note: if `Enum` implemented `Clone`, you could clone the value
+  --> $DIR/issue-17385.rs:3:1
+   |
+LL | enum Enum {
+   | ^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-17551.stderr b/tests/ui/issues/issue-17551.stderr
index 68f54a31084..b9cb76fc298 100644
--- a/tests/ui/issues/issue-17551.stderr
+++ b/tests/ui/issues/issue-17551.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `B<T>`
+error[E0282]: type annotations needed for `B<_>`
   --> $DIR/issue-17551.rs:6:9
    |
 LL |     let foo = B(marker::PhantomData);
diff --git a/tests/ui/issues/issue-21596.rs b/tests/ui/issues/issue-21596.rs
deleted file mode 100644
index 79f6c91d9ac..00000000000
--- a/tests/ui/issues/issue-21596.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    let x = 8u8;
-    let z: *const u8 = &x;
-    println!("{}", z.to_string());  //~ ERROR E0599
-}
diff --git a/tests/ui/issues/issue-21596.stderr b/tests/ui/issues/issue-21596.stderr
deleted file mode 100644
index 8a7fca5f436..00000000000
--- a/tests/ui/issues/issue-21596.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-21596.rs:4:22
-   |
-LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
-   |
-   = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
-   = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
-   = note: the following trait bounds were not satisfied:
-           `*const u8: std::fmt::Display`
-           which is required by `*const u8: ToString`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/issues/issue-23046.stderr b/tests/ui/issues/issue-23046.stderr
index b6e23814543..f70ac0c9f38 100644
--- a/tests/ui/issues/issue-23046.stderr
+++ b/tests/ui/issues/issue-23046.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Expr<'_, VAR>`
+error[E0282]: type annotations needed for `Expr<'_, _>`
   --> $DIR/issue-23046.rs:17:15
    |
 LL |     let ex = |x| {
diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs
index 152e69ebc87..d1a9e37251e 100644
--- a/tests/ui/issues/issue-24357.rs
+++ b/tests/ui/issues/issue-24357.rs
@@ -1,4 +1,4 @@
-struct NoCopy;
+struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value
 fn main() {
    let x = NoCopy;
    //~^ NOTE move occurs because `x` has type `NoCopy`
diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr
index 08a5a8ac56e..6d50eea7e21 100644
--- a/tests/ui/issues/issue-24357.stderr
+++ b/tests/ui/issues/issue-24357.stderr
@@ -11,6 +11,12 @@ LL |    let f = move || { let y = x; };
 ...
 LL |    let z = x;
    |            ^ value used here after move
+   |
+note: if `NoCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-24357.rs:1:1
+   |
+LL | struct NoCopy;
+   | ^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-2590.stderr b/tests/ui/issues/issue-2590.stderr
index 517b4814eae..822856652e9 100644
--- a/tests/ui/issues/issue-2590.stderr
+++ b/tests/ui/issues/issue-2590.stderr
@@ -3,6 +3,11 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared referenc
    |
 LL |         self.tokens
    |         ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec<isize>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         self.tokens.clone()
+   |                    ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-27042.stderr b/tests/ui/issues/issue-27042.stderr
index 01532de999e..ba39399e46e 100644
--- a/tests/ui/issues/issue-27042.stderr
+++ b/tests/ui/issues/issue-27042.stderr
@@ -19,7 +19,7 @@ LL |         loop { break };
    |         |
    |         this loop is expected to be of type `i32`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         loop { break 42 };
    |                      ++
diff --git a/tests/ui/issues/issue-28433.stderr b/tests/ui/issues/issue-28433.stderr
index 5fb8a89621c..0fa67e35f1d 100644
--- a/tests/ui/issues/issue-28433.stderr
+++ b/tests/ui/issues/issue-28433.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-28433.rs:2:5
    |
 LL |     pub Duck,
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: enum variants and their fields always share the visibility of the enum they are in
 
@@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-28433.rs:5:5
    |
 LL |     pub(crate) Dove
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ help: remove the qualifier
    |
    = note: enum variants and their fields always share the visibility of the enum they are in
 
diff --git a/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr b/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr
index 7976d090542..d27b6e6324f 100644
--- a/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr
+++ b/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr
@@ -8,6 +8,10 @@ help: consider borrowing here
    |
 LL |     let e = &f.v[0];
    |             +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let e = f.v[0].clone();
+   |                   ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr
index 1967b51128f..b765d2f087d 100644
--- a/tests/ui/issues/issue-50582.stderr
+++ b/tests/ui/issues/issue-50582.stderr
@@ -16,15 +16,15 @@ LL |     Vec::<[(); 1 + for x in 0..1 {}]>::new();
    |
    = help: the trait `Add<()>` is not implemented for `{integer}`
    = help: the following other types implement trait `Add<Rhs>`:
+             <&'a f128 as Add<f128>>
+             <&'a f16 as Add<f16>>
              <&'a f32 as Add<f32>>
              <&'a f64 as Add<f64>>
              <&'a i128 as Add<i128>>
              <&'a i16 as Add<i16>>
              <&'a i32 as Add<i32>>
              <&'a i64 as Add<i64>>
-             <&'a i8 as Add<i8>>
-             <&'a isize as Add<isize>>
-           and 48 others
+           and 56 others
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-52262.stderr b/tests/ui/issues/issue-52262.stderr
index ce8e6fe2bf8..51959f22b97 100644
--- a/tests/ui/issues/issue-52262.stderr
+++ b/tests/ui/issues/issue-52262.stderr
@@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference
    |
 LL |                 String::from_utf8(*key).unwrap()
    |                                   ^^^^ move occurs because `*key` has type `Vec<u8>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -                 String::from_utf8(*key).unwrap()
+LL +                 String::from_utf8(key.clone()).unwrap()
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-98299.stderr b/tests/ui/issues/issue-98299.stderr
index e99d8e5cc80..becf16d1db9 100644
--- a/tests/ui/issues/issue-98299.stderr
+++ b/tests/ui/issues/issue-98299.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `SmallCString<N>`
+error[E0282]: type annotations needed for `SmallCString<_>`
   --> $DIR/issue-98299.rs:4:36
    |
 LL |     SmallCString::try_from(p).map(|cstr| cstr);
diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs
new file mode 100644
index 00000000000..8426b0021f4
--- /dev/null
+++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust/issues/123844
+// An uninitialized refutable let should not suggest `let else`, as it can't be used with deferred
+// initialization.
+
+fn main() {
+    let Some(x); //~ ERROR refutable pattern in local binding
+    x = 1;
+}
diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr
new file mode 100644
index 00000000000..13312306c07
--- /dev/null
+++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr
@@ -0,0 +1,13 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/uninitialized-refutable-let-issue-123844.rs:6:9
+   |
+LL |     let Some(x);
+   |         ^^^^^^^ pattern `None` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `Option<i32>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs
new file mode 100644
index 00000000000..caae48dfd3b
--- /dev/null
+++ b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs
@@ -0,0 +1,9 @@
+//@ edition:2021
+macro_rules! a {
+    ( ) => {
+        impl<'b> c for d {
+            e::<f'g> //~ ERROR prefix `f` is unknown
+        }
+    };
+}
+fn main() {}
diff --git a/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr
new file mode 100644
index 00000000000..ecce2c66504
--- /dev/null
+++ b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr
@@ -0,0 +1,14 @@
+error: prefix `f` is unknown
+  --> $DIR/dont-ice-on-invalid-lifetime-in-macro-definition.rs:5:17
+   |
+LL |             e::<f'g>
+   |                 ^ unknown prefix
+   |
+   = note: prefixed identifiers and literals are reserved since Rust 2021
+help: consider inserting whitespace here
+   |
+LL |             e::<f 'g>
+   |                  +
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
index 0ae227da5f1..52781d9c6d8 100644
--- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
@@ -3,5 +3,6 @@
 //@[rust2021] edition:2021
 fn main() {
     println!('hello world');
-    //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal
+    //~^ ERROR unterminated character literal
+    //[rust2021]~| ERROR prefix `world` is unknown
 }
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
index 06f12742667..4170560cfcb 100644
--- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
@@ -1,3 +1,15 @@
+error: prefix `world` is unknown
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21
+   |
+LL |     println!('hello world');
+   |                     ^^^^^ unknown prefix
+   |
+   = note: prefixed identifiers and literals are reserved since Rust 2021
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
 error[E0762]: unterminated character literal
   --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
    |
@@ -9,6 +21,6 @@ help: if you meant to write a string literal, use double quotes
 LL |     println!("hello world");
    |              ~           ~
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs
new file mode 100644
index 00000000000..f0c7ad8f82b
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs
@@ -0,0 +1,9 @@
+//@edition:2021
+macro_rules! foo {
+    () => {
+        println!('hello world');
+        //~^ ERROR unterminated character literal
+        //~| ERROR prefix `world` is unknown
+    }
+}
+fn main() {}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr
new file mode 100644
index 00000000000..af42b5b7f7b
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr
@@ -0,0 +1,26 @@
+error: prefix `world` is unknown
+  --> $DIR/lex-bad-str-literal-as-char-4.rs:4:25
+   |
+LL |         println!('hello world');
+   |                         ^^^^^ unknown prefix
+   |
+   = note: prefixed identifiers and literals are reserved since Rust 2021
+help: if you meant to write a string literal, use double quotes
+   |
+LL |         println!("hello world");
+   |                  ~           ~
+
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-4.rs:4:30
+   |
+LL |         println!('hello world');
+   |                              ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |         println!("hello world");
+   |                  ~           ~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/linkage-attr/uikit-framework.rs b/tests/ui/linkage-attr/uikit-framework.rs
new file mode 100644
index 00000000000..fca0332384a
--- /dev/null
+++ b/tests/ui/linkage-attr/uikit-framework.rs
@@ -0,0 +1,25 @@
+//! Check that linking to UIKit on platforms where that is available works.
+//@ revisions: ios tvos watchos visionos
+//@ [ios]only-ios
+//@ [tvos]only-tvos
+//@ [watchos]only-watchos
+//@ [visionos]only-visionos
+//@ build-pass
+
+use std::ffi::{c_char, c_int, c_void};
+
+#[link(name = "UIKit", kind = "framework")]
+extern "C" {
+    pub fn UIApplicationMain(
+        argc: c_int,
+        argv: *const c_char,
+        principalClassName: *const c_void,
+        delegateClassName: *const c_void,
+    ) -> c_int;
+}
+
+pub fn main() {
+    unsafe {
+        UIApplicationMain(0, core::ptr::null(), core::ptr::null(), core::ptr::null());
+    }
+}
diff --git a/tests/ui/lint/unused/issue-59896.rs b/tests/ui/lint/unused/issue-59896.rs
index ff9f19acf84..a98017524f5 100644
--- a/tests/ui/lint/unused/issue-59896.rs
+++ b/tests/ui/lint/unused/issue-59896.rs
@@ -1,9 +1,10 @@
+//@ check-pass
 #![deny(unused_imports)]
 
 struct S;
 
 fn main() {
-    use S;  //~ ERROR the item `S` is imported redundantly
+    use S;  //FIXME(unused_imports): ~ ERROR the item `S` is imported redundantly
 
     let _s = S;
 }
diff --git a/tests/ui/lint/unused/issue-59896.stderr b/tests/ui/lint/unused/issue-59896.stderr
deleted file mode 100644
index 3e8298c6b72..00000000000
--- a/tests/ui/lint/unused/issue-59896.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: the item `S` is imported redundantly
-  --> $DIR/issue-59896.rs:6:9
-   |
-LL | struct S;
-   | --------- the item `S` is already defined here
-...
-LL |     use S;
-   |         ^
-   |
-note: the lint level is defined here
-  --> $DIR/issue-59896.rs:1:9
-   |
-LL | #![deny(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs
new file mode 100644
index 00000000000..59bb65a357b
--- /dev/null
+++ b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs
@@ -0,0 +1,39 @@
+//@ run-pass
+
+#![warn(unused_parens)]
+#![allow(dead_code)]
+
+trait Foo {
+    fn bar();
+    fn tar();
+}
+
+macro_rules! unused_parens {
+    ($ty:ident) => {
+        impl<$ty: Foo> Foo for ($ty,) {
+            fn bar() { <$ty>::bar() }
+            fn tar() {}
+        }
+    };
+
+    ($ty:ident $(, $rest:ident)*) => {
+        impl<$ty: Foo, $($rest: Foo),*> Foo for ($ty, $($rest),*) {
+            fn bar() {
+                <$ty>::bar();
+                <($($rest),*)>::bar() //~WARN unnecessary parentheses around type
+            }
+            fn tar() {
+              let (_t) = 1; //~WARN unnecessary parentheses around pattern
+                            //~| WARN unnecessary parentheses around pattern
+              let (_t1,) = (1,);
+              let (_t2, _t3) = (1, 2);
+            }
+        }
+
+        unused_parens!($($rest),*);
+    }
+}
+
+unused_parens!(T1, T2, T3);
+
+fn main() {}
diff --git a/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr
new file mode 100644
index 00000000000..b1390debec7
--- /dev/null
+++ b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr
@@ -0,0 +1,40 @@
+warning: unnecessary parentheses around pattern
+  --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19
+   |
+LL |               let (_t) = 1;
+   |                   ^^^^
+...
+LL | unused_parens!(T1, T2, T3);
+   | -------------------------- in this macro invocation
+   |
+note: the lint level is defined here
+  --> $DIR/unused-parens-in-macro-issue-120642.rs:3:9
+   |
+LL | #![warn(unused_parens)]
+   |         ^^^^^^^^^^^^^
+   = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: unnecessary parentheses around type
+  --> $DIR/unused-parens-in-macro-issue-120642.rs:23:18
+   |
+LL |                 <($($rest),*)>::bar()
+   |                  ^^^^^^^^^^^^
+...
+LL | unused_parens!(T1, T2, T3);
+   | -------------------------- in this macro invocation
+   |
+   = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: unnecessary parentheses around pattern
+  --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19
+   |
+LL |               let (_t) = 1;
+   |                   ^^^^
+...
+LL | unused_parens!(T1, T2, T3);
+   | -------------------------- in this macro invocation
+   |
+   = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
index 28d1fea98b5..797e57f48e9 100644
--- a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
+++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
@@ -9,7 +9,7 @@ pub mod bar {
 use bar::*;
 
 pub fn warning() -> Foo {
-    use bar::Foo; //~ WARNING imported redundantly
+    use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly
     Foo(Bar('a'))
 }
 
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
deleted file mode 100644
index 2c3b3345270..00000000000
--- a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the item `Foo` is imported redundantly
-  --> $DIR/use-redundant-glob-parent.rs:12:9
-   |
-LL | use bar::*;
-   |     ------ the item `Foo` is already imported here
-...
-LL |     use bar::Foo;
-   |         ^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/use-redundant-glob-parent.rs:2:9
-   |
-LL | #![warn(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.rs b/tests/ui/lint/use-redundant/use-redundant-glob.rs
index 3d3fe2579b5..e5835be89d8 100644
--- a/tests/ui/lint/use-redundant/use-redundant-glob.rs
+++ b/tests/ui/lint/use-redundant/use-redundant-glob.rs
@@ -8,7 +8,7 @@ pub mod bar {
 
 pub fn warning() -> bar::Foo {
     use bar::*;
-    use bar::Foo; //~ WARNING imported redundantly
+    use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly
     Foo(Bar('a'))
 }
 
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.stderr b/tests/ui/lint/use-redundant/use-redundant-glob.stderr
deleted file mode 100644
index d3b406d82b6..00000000000
--- a/tests/ui/lint/use-redundant/use-redundant-glob.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-warning: the item `Foo` is imported redundantly
-  --> $DIR/use-redundant-glob.rs:11:9
-   |
-LL |     use bar::*;
-   |         ------ the item `Foo` is already imported here
-LL |     use bar::Foo;
-   |         ^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/use-redundant-glob.rs:2:9
-   |
-LL | #![warn(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs
index d0fb3454d3f..2db3435d46d 100644
--- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs
+++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs
@@ -23,7 +23,8 @@ mod foo {
 fn main() {
 
     {
-        use std::string::String; //~ WARNING the item `String` is imported redundantly
+        use std::string::String;
+        //FIXME(unused_imports): ~^ WARNING the item `String` is imported redundantly
         // 'String' from 'std::string::String'.
         let s = String::new();
         println!("{}", s);
diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr
deleted file mode 100644
index b8832a31783..00000000000
--- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the item `String` is imported redundantly
-  --> $DIR/use-redundant-issue-71450.rs:26:13
-   |
-LL |         use std::string::String;
-   |             ^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `String` is already defined here
-   |
-note: the lint level is defined here
-  --> $DIR/use-redundant-issue-71450.rs:3:9
-   |
-LL | #![warn(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs
index ae5118b2729..62f50c8a0df 100644
--- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs
@@ -2,11 +2,15 @@
 #![warn(unused_imports)]
 
 
-use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly
-use std::option::Option::None; //~ WARNING the item `None` is imported redundantly
+use std::option::Option::Some;
+//FIXME(unused_imports): ~^ WARNING the item `Some` is imported redundantly
+use std::option::Option::None;
+//FIXME(unused_imports): ~ WARNING the item `None` is imported redundantly
 
-use std::result::Result::Ok;//~ WARNING the item `Ok` is imported redundantly
-use std::result::Result::Err;//~ WARNING the item `Err` is imported redundantly
+use std::result::Result::Ok;
+//FIXME(unused_imports): ~^ WARNING the item `Ok` is imported redundantly
+use std::result::Result::Err;
+//FIXME(unused_imports): ~^ WARNING the item `Err` is imported redundantly
 use std::convert::{TryFrom, TryInto};
 
 fn main() {
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr
deleted file mode 100644
index 1b09df911eb..00000000000
--- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-warning: the item `Some` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2015.rs:5:5
-   |
-LL | use std::option::Option::Some;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `Some` is already defined here
-   |
-note: the lint level is defined here
-  --> $DIR/use-redundant-prelude-rust-2015.rs:2:9
-   |
-LL | #![warn(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-warning: the item `None` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2015.rs:6:5
-   |
-LL | use std::option::Option::None;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `None` is already defined here
-
-warning: the item `Ok` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2015.rs:8:5
-   |
-LL | use std::result::Result::Ok;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `Ok` is already defined here
-
-warning: the item `Err` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2015.rs:9:5
-   |
-LL | use std::result::Result::Err;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `Err` is already defined here
-
-warning: 4 warnings emitted
-
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs
index cb4dcb6c0bd..1baa1ac1b8c 100644
--- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs
@@ -2,8 +2,10 @@
 //@ edition:2021
 #![warn(unused_imports)]
 
-use std::convert::TryFrom;//~ WARNING the item `TryFrom` is imported redundantly
-use std::convert::TryInto;//~ WARNING the item `TryInto` is imported redundantly
+use std::convert::TryFrom;
+//FIXME(unused_imports): ~^ WARNING the item `TryFrom` is imported redundantly
+use std::convert::TryInto;
+//FIXME(unused_imports): ~^ WARNING the item `TryInto` is imported redundantly
 
 fn main() {
     let _e: Result<i32, _> = 8u8.try_into();
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr
deleted file mode 100644
index 542356dc996..00000000000
--- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-warning: the item `TryFrom` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2021.rs:5:5
-   |
-LL | use std::convert::TryFrom;
-   |     ^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `TryFrom` is already defined here
-   |
-note: the lint level is defined here
-  --> $DIR/use-redundant-prelude-rust-2021.rs:3:9
-   |
-LL | #![warn(unused_imports)]
-   |         ^^^^^^^^^^^^^^
-
-warning: the item `TryInto` is imported redundantly
-  --> $DIR/use-redundant-prelude-rust-2021.rs:6:5
-   |
-LL | use std::convert::TryInto;
-   |     ^^^^^^^^^^^^^^^^^^^^^
-  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
-   |
-   = note: the item `TryInto` is already defined here
-
-warning: 2 warnings emitted
-
diff --git a/tests/ui/lint/use-redundant/use-redundant.rs b/tests/ui/lint/use-redundant/use-redundant.rs
index 88d3ee75a3f..9e4902af34b 100644
--- a/tests/ui/lint/use-redundant/use-redundant.rs
+++ b/tests/ui/lint/use-redundant/use-redundant.rs
@@ -18,7 +18,7 @@ use m1::*; //~ WARNING unused import
 use m2::*; //~ WARNING unused import
 
 fn main() {
-    use crate::foo::Bar; //~ WARNING imported redundantly
+    use crate::foo::Bar; //FIXME(unused_imports): ~ WARNING imported redundantly
     let _a: Bar = 3;
     baz();
 
diff --git a/tests/ui/lint/use-redundant/use-redundant.stderr b/tests/ui/lint/use-redundant/use-redundant.stderr
index c861a1956e1..224e8411237 100644
--- a/tests/ui/lint/use-redundant/use-redundant.stderr
+++ b/tests/ui/lint/use-redundant/use-redundant.stderr
@@ -16,14 +16,5 @@ warning: unused import: `m2::*`
 LL | use m2::*;
    |     ^^^^^
 
-warning: the item `Bar` is imported redundantly
-  --> $DIR/use-redundant.rs:21:9
-   |
-LL | use crate::foo::Bar;
-   |     --------------- the item `Bar` is already imported here
-...
-LL |     use crate::foo::Bar;
-   |         ^^^^^^^^^^^^^^^
-
-warning: 3 warnings emitted
+warning: 2 warnings emitted
 
diff --git a/tests/ui/loops/loop-break-value.rs b/tests/ui/loops/loop-break-value.rs
index c35200520cb..d509fc16570 100644
--- a/tests/ui/loops/loop-break-value.rs
+++ b/tests/ui/loops/loop-break-value.rs
@@ -23,6 +23,10 @@ fn main() {
         };
     };
 
+    let _: Option<String> = loop {
+        break; //~ ERROR mismatched types
+    };
+
     'while_loop: while true { //~ WARN denote infinite loops with
         break;
         break (); //~ ERROR `break` with value from a `while` loop
diff --git a/tests/ui/loops/loop-break-value.stderr b/tests/ui/loops/loop-break-value.stderr
index a691960f962..0093182422e 100644
--- a/tests/ui/loops/loop-break-value.stderr
+++ b/tests/ui/loops/loop-break-value.stderr
@@ -1,5 +1,5 @@
 warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/loop-break-value.rs:136:17
+  --> $DIR/loop-break-value.rs:140:17
    |
 LL |     'a: loop {
    |     -- first declared here
@@ -8,7 +8,7 @@ LL |         let _ = 'a: loop {
    |                 ^^ label `'a` already in scope
 
 warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/loop-break-value.rs:148:17
+  --> $DIR/loop-break-value.rs:152:17
    |
 LL |     'a: loop {
    |     -- first declared here
@@ -17,7 +17,7 @@ LL |         let _ = 'a: loop {
    |                 ^^ label `'a` already in scope
 
 error[E0425]: cannot find value `LOOP` in this scope
-  --> $DIR/loop-break-value.rs:95:15
+  --> $DIR/loop-break-value.rs:99:15
    |
 LL |     'LOOP: for _ in 0 .. 9 {
    |     ----- a label with a similar name exists
@@ -28,7 +28,7 @@ LL |         break LOOP;
    |               help: use the similarly named label: `'LOOP`
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/loop-break-value.rs:26:5
+  --> $DIR/loop-break-value.rs:30:5
    |
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
@@ -36,7 +36,7 @@ LL |     'while_loop: while true {
    = note: `#[warn(while_true)]` on by default
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:28:9
+  --> $DIR/loop-break-value.rs:32:9
    |
 LL |     'while_loop: while true {
    |     ----------------------- you can't `break` with a value in a `while` loop
@@ -54,7 +54,7 @@ LL |         break 'while_loop;
    |               ~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:30:13
+  --> $DIR/loop-break-value.rs:34:13
    |
 LL |     'while_loop: while true {
    |     ----------------------- you can't `break` with a value in a `while` loop
@@ -68,7 +68,7 @@ LL |             break 'while_loop;
    |             ~~~~~~~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:38:12
+  --> $DIR/loop-break-value.rs:42:12
    |
 LL |     while let Some(_) = Some(()) {
    |     ---------------------------- you can't `break` with a value in a `while` loop
@@ -81,7 +81,7 @@ LL |         if break {
    |            ~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:43:9
+  --> $DIR/loop-break-value.rs:47:9
    |
 LL |     while let Some(_) = Some(()) {
    |     ---------------------------- you can't `break` with a value in a `while` loop
@@ -94,7 +94,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:49:13
+  --> $DIR/loop-break-value.rs:53:13
    |
 LL |     'while_let_loop: while let Some(_) = Some(()) {
    |     --------------------------------------------- you can't `break` with a value in a `while` loop
@@ -108,7 +108,7 @@ LL |             break 'while_let_loop;
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:56:9
+  --> $DIR/loop-break-value.rs:60:9
    |
 LL |     for _ in &[1,2,3] {
    |     ----------------- you can't `break` with a value in a `for` loop
@@ -121,7 +121,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:57:9
+  --> $DIR/loop-break-value.rs:61:9
    |
 LL |     for _ in &[1,2,3] {
    |     ----------------- you can't `break` with a value in a `for` loop
@@ -135,7 +135,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:64:13
+  --> $DIR/loop-break-value.rs:68:13
    |
 LL |     'for_loop: for _ in &[1,2,3] {
    |     ---------------------------- you can't `break` with a value in a `for` loop
@@ -191,7 +191,24 @@ LL |             break 'outer_loop "nope";
    |                               ^^^^^^ expected `i32`, found `&str`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:73:26
+  --> $DIR/loop-break-value.rs:27:9
+   |
+LL |     let _: Option<String> = loop {
+   |         -                   ---- this loop is expected to be of type `Option<String>`
+   |         |
+   |         expected because of this assignment
+LL |         break;
+   |         ^^^^^ expected `Option<String>`, found `()`
+   |
+   = note:   expected enum `Option<String>`
+           found unit type `()`
+help: give the `break` a value of the expected type
+   |
+LL |         break None;
+   |               ++++
+
+error[E0308]: mismatched types
+  --> $DIR/loop-break-value.rs:77:26
    |
 LL |                 break;
    |                 ----- expected because of this `break`
@@ -199,7 +216,7 @@ LL |                 break 'c 123;
    |                          ^^^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:80:15
+  --> $DIR/loop-break-value.rs:84:15
    |
 LL |         break (break, break);
    |               ^-----^^-----^
@@ -212,7 +229,7 @@ LL |         break (break, break);
                   found tuple `(!, !)`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:85:15
+  --> $DIR/loop-break-value.rs:89:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -220,20 +237,20 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:90:9
+  --> $DIR/loop-break-value.rs:94:9
    |
 LL |         break 2;
    |         ------- expected because of this `break`
 LL |         break;
    |         ^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break value;
    |               +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:108:9
+  --> $DIR/loop-break-value.rs:112:9
    |
 LL |                     break 'a 1;
    |                     ---------- expected because of this `break`
@@ -241,13 +258,13 @@ LL |                     break 'a 1;
 LL |         break;
    |         ^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break value;
    |               +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:120:9
+  --> $DIR/loop-break-value.rs:124:9
    |
 LL |                     break 'a 1;
    |                     ---------- expected because of this `break`
@@ -255,13 +272,13 @@ LL |                     break 'a 1;
 LL |         break 'a;
    |         ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break 'a value;
    |                  +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:131:15
+  --> $DIR/loop-break-value.rs:135:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -270,7 +287,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:140:17
+  --> $DIR/loop-break-value.rs:144:17
    |
 LL |             break 2;
    |             ------- expected because of this `break`
@@ -278,13 +295,13 @@ LL |             loop {
 LL |                 break 'a;
    |                 ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |                 break 'a value;
    |                          +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:143:15
+  --> $DIR/loop-break-value.rs:147:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -293,7 +310,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:152:17
+  --> $DIR/loop-break-value.rs:156:17
    |
 LL |             break 'a 2;
    |             ---------- expected because of this `break`
@@ -301,13 +318,13 @@ LL |             loop {
 LL |                 break 'a;
    |                 ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |                 break 'a value;
    |                          +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:155:15
+  --> $DIR/loop-break-value.rs:159:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -316,7 +333,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:159:15
+  --> $DIR/loop-break-value.rs:163:15
    |
 LL | fn main() {
    |          - expected `()` because of this return type
@@ -326,7 +343,7 @@ LL |     loop { // point at the return type
 LL |         break 2;
    |               ^ expected `()`, found integer
 
-error: aborting due to 25 previous errors; 3 warnings emitted
+error: aborting due to 26 previous errors; 3 warnings emitted
 
 Some errors have detailed explanations: E0308, E0425, E0571.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/loops/loop-labeled-break-value.stderr b/tests/ui/loops/loop-labeled-break-value.stderr
index 694d6c306f6..3be62316e34 100644
--- a/tests/ui/loops/loop-labeled-break-value.stderr
+++ b/tests/ui/loops/loop-labeled-break-value.stderr
@@ -7,7 +7,7 @@ LL |         let _: i32 = loop { break };
    |             |        this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = loop { break 42 };
    |                                   ++
@@ -21,7 +21,7 @@ LL |         let _: i32 = 'inner: loop { break 'inner };
    |             |                this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = 'inner: loop { break 'inner 42 };
    |                                                  ++
@@ -35,7 +35,7 @@ LL |         let _: i32 = 'inner2: loop { loop { break 'inner2 } };
    |             |                 this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = 'inner2: loop { loop { break 'inner2 42 } };
    |                                                           ++
diff --git a/tests/ui/loops/loop-proper-liveness.stderr b/tests/ui/loops/loop-proper-liveness.stderr
index bcd6eb353e5..cd4c064bcd1 100644
--- a/tests/ui/loops/loop-proper-liveness.stderr
+++ b/tests/ui/loops/loop-proper-liveness.stderr
@@ -10,8 +10,8 @@ LL |     println!("{:?}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/loops/loop-properly-diverging-2.stderr b/tests/ui/loops/loop-properly-diverging-2.stderr
index c9f27a6a672..ba615f9ae4f 100644
--- a/tests/ui/loops/loop-properly-diverging-2.stderr
+++ b/tests/ui/loops/loop-properly-diverging-2.stderr
@@ -7,7 +7,7 @@ LL |   let x: i32 = loop { break };
    |       |        this loop is expected to be of type `i32`
    |       expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |   let x: i32 = loop { break 42 };
    |                             ++
diff --git a/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index 0a022dc3984..b2d2d039ff6 100644
--- a/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Vec<T>`
+error[E0282]: type annotations needed for `Vec<_>`
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
    |
 LL |     let mut x = Vec::new();
diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.rs b/tests/ui/methods/suggest-convert-ptr-to-ref.rs
new file mode 100644
index 00000000000..ccce3c65470
--- /dev/null
+++ b/tests/ui/methods/suggest-convert-ptr-to-ref.rs
@@ -0,0 +1,17 @@
+fn main() {
+    let mut x = 8u8;
+    let z: *const u8 = &x;
+    // issue #21596
+    println!("{}", z.to_string()); //~ ERROR E0599
+
+    let t: *mut u8 = &mut x;
+    println!("{}", t.to_string()); //~ ERROR E0599
+    t.make_ascii_lowercase(); //~ ERROR E0599
+
+    // suggest `as_mut` simply because the name is similar
+    let _ = t.as_mut_ref(); //~ ERROR E0599
+    let _ = t.as_ref_mut(); //~ ERROR E0599
+
+    // no ptr-to-ref suggestion
+    z.make_ascii_lowercase(); //~ ERROR E0599
+}
diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
new file mode 100644
index 00000000000..69b20d57be8
--- /dev/null
+++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
@@ -0,0 +1,70 @@
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
+  --> $DIR/suggest-convert-ptr-to-ref.rs:5:22
+   |
+LL |     println!("{}", z.to_string());
+   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
+   |
+note: the method `to_string` exists on the type `&u8`
+  --> $SRC_DIR/alloc/src/string.rs:LL:COL
+   = note: you might want to use the unsafe method `<*const T>::as_ref` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*const T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
+   = note: the following trait bounds were not satisfied:
+           `*const u8: std::fmt::Display`
+           which is required by `*const u8: ToString`
+
+error[E0599]: `*mut u8` doesn't implement `std::fmt::Display`
+  --> $DIR/suggest-convert-ptr-to-ref.rs:8:22
+   |
+LL |     println!("{}", t.to_string());
+   |                      ^^^^^^^^^ `*mut u8` cannot be formatted with the default formatter
+   |
+note: the method `to_string` exists on the type `&&mut u8`
+  --> $SRC_DIR/alloc/src/string.rs:LL:COL
+   = note: you might want to use the unsafe method `<*mut T>::as_ref` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*mut T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref-1
+   = note: the following trait bounds were not satisfied:
+           `*mut u8: std::fmt::Display`
+           which is required by `*mut u8: ToString`
+
+error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:9:7
+   |
+LL |     t.make_ascii_lowercase();
+   |       ^^^^^^^^^^^^^^^^^^^^ method not found in `*mut u8`
+   |
+note: the method `make_ascii_lowercase` exists on the type `&mut u8`
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+   = note: you might want to use the unsafe method `<*mut T>::as_mut` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*mut T>::as_mut` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut
+
+error[E0599]: no method named `as_mut_ref` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:12:15
+   |
+LL |     let _ = t.as_mut_ref();
+   |               ^^^^^^^^^^
+   |
+help: there is a method `as_mut` with a similar name
+   |
+LL |     let _ = t.as_mut();
+   |               ~~~~~~
+
+error[E0599]: no method named `as_ref_mut` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:13:15
+   |
+LL |     let _ = t.as_ref_mut();
+   |               ^^^^^^^^^^
+   |
+help: there is a method `as_mut` with a similar name
+   |
+LL |     let _ = t.as_mut();
+   |               ~~~~~~
+
+error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*const u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:16:7
+   |
+LL |     z.make_ascii_lowercase();
+   |       ^^^^^^^^^^^^^^^^^^^^ method not found in `*const u8`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr
index 1f04d119b56..838eaffb5a0 100644
--- a/tests/ui/mir/issue-102389.stderr
+++ b/tests/ui/mir/issue-102389.stderr
@@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*inbounds` which is behind a shared reference
    |
 LL |     array[*inbounds as usize]
    |           ^^^^^^^^^ move occurs because `*inbounds` has type `Enum`, which does not implement the `Copy` trait
+   |
+note: if `Enum` implemented `Clone`, you could clone the value
+  --> $DIR/issue-102389.rs:1:1
+   |
+LL | enum Enum { A, B, C }
+   | ^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr
index f8047c8e2d4..099c580a056 100644
--- a/tests/ui/mismatched_types/binops.stderr
+++ b/tests/ui/mismatched_types/binops.stderr
@@ -6,15 +6,15 @@ LL |     1 + Some(1);
    |
    = help: the trait `Add<Option<{integer}>>` is not implemented for `{integer}`
    = help: the following other types implement trait `Add<Rhs>`:
+             <&'a f128 as Add<f128>>
+             <&'a f16 as Add<f16>>
              <&'a f32 as Add<f32>>
              <&'a f64 as Add<f64>>
              <&'a i128 as Add<i128>>
              <&'a i16 as Add<i16>>
              <&'a i32 as Add<i32>>
              <&'a i64 as Add<i64>>
-             <&'a i8 as Add<i8>>
-             <&'a isize as Add<isize>>
-           and 48 others
+           and 56 others
 
 error[E0277]: cannot subtract `Option<{integer}>` from `usize`
   --> $DIR/binops.rs:3:16
@@ -37,15 +37,15 @@ LL |     3 * ();
    |
    = help: the trait `Mul<()>` is not implemented for `{integer}`
    = help: the following other types implement trait `Mul<Rhs>`:
+             <&'a f128 as Mul<f128>>
+             <&'a f16 as Mul<f16>>
              <&'a f32 as Mul<f32>>
              <&'a f64 as Mul<f64>>
              <&'a i128 as Mul<i128>>
              <&'a i16 as Mul<i16>>
              <&'a i32 as Mul<i32>>
              <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+           and 57 others
 
 error[E0277]: cannot divide `{integer}` by `&str`
   --> $DIR/binops.rs:5:7
@@ -55,15 +55,15 @@ LL |     4 / "";
    |
    = help: the trait `Div<&str>` is not implemented for `{integer}`
    = help: the following other types implement trait `Div<Rhs>`:
+             <&'a f128 as Div<f128>>
+             <&'a f16 as Div<f16>>
              <&'a f32 as Div<f32>>
              <&'a f64 as Div<f64>>
              <&'a i128 as Div<i128>>
              <&'a i16 as Div<i16>>
              <&'a i32 as Div<i32>>
              <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+           and 62 others
 
 error[E0277]: can't compare `{integer}` with `String`
   --> $DIR/binops.rs:6:7
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs
index 56c225bab8c..86f389cb3af 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs
@@ -3,6 +3,10 @@
 // 'value moved in previous iteration of loop' message
 
 struct NonCopy;
+//~^ NOTE if `NonCopy` implemented `Clone`
+//~| NOTE if `NonCopy` implemented `Clone`
+//~| NOTE if `NonCopy` implemented `Clone`
+//~| NOTE if `NonCopy` implemented `Clone`
 
 fn good() {
     loop {
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
index 7e119fe8cda..35216f8a66f 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:20:22
+  --> $DIR/issue-72649-uninit-in-loop.rs:24:22
    |
 LL |         let value = NonCopy{};
    |             ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -9,9 +9,15 @@ LL |         let _used = value;
 LL |
 LL |         let _used2 = value;
    |                      ^^^^^ value used here after move
+   |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-72649-uninit-in-loop.rs:5:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:32:26
+  --> $DIR/issue-72649-uninit-in-loop.rs:36:26
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -23,9 +29,15 @@ LL |         let _used = value;
 ...
 LL |             let _used2 = value;
    |                          ^^^^^ value used here after move
+   |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-72649-uninit-in-loop.rs:5:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:42:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:46:21
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -34,9 +46,15 @@ LL |     loop {
    |     ---- inside of this loop
 LL |         let _used = value;
    |                     ^^^^^ value moved here, in previous iteration of loop
+   |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-72649-uninit-in-loop.rs:5:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:53:22
+  --> $DIR/issue-72649-uninit-in-loop.rs:57:22
    |
 LL |     let mut value = NonCopy{};
    |         --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -45,9 +63,15 @@ LL |     loop {
    |     ---- inside of this loop
 LL |         let _used2 = value;
    |                      ^^^^^ value moved here, in previous iteration of loop
+   |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-72649-uninit-in-loop.rs:5:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^
 
 error[E0381]: used binding `value` isn't initialized
-  --> $DIR/issue-72649-uninit-in-loop.rs:61:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:65:21
    |
 LL |         let value: NonCopy;
    |             ----- binding declared here but left uninitialized
@@ -56,11 +80,11 @@ LL |         let _used = value;
    |
 help: consider assigning a value
    |
-LL |         let value: NonCopy = todo!();
-   |                            +++++++++
+LL |         let value: NonCopy = value;
+   |                            +++++++
 
 error[E0381]: used binding `value` isn't initialized
-  --> $DIR/issue-72649-uninit-in-loop.rs:69:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:73:21
    |
 LL |     let mut value: NonCopy;
    |         --------- binding declared here but left uninitialized
@@ -70,8 +94,8 @@ LL |         let _used = value;
    |
 help: consider assigning a value
    |
-LL |     let mut value: NonCopy = todo!();
-   |                            +++++++++
+LL |     let mut value: NonCopy = value;
+   |                            +++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr
index 6f04105a35e..b6ad906bbdb 100644
--- a/tests/ui/moves/issue-75904-move-closure-loop.stderr
+++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr
@@ -4,11 +4,18 @@ error[E0382]: use of moved value: `a`
 LL |     let mut a = NotCopy;
    |         ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         || {
    |         ^^ value moved into closure here, in previous iteration of loop
 LL |             &mut a;
 LL |             a;
    |             - use occurs due to use in closure
+   |
+note: if `NotCopy` implemented `Clone`, you could clone the value
+  --> $DIR/issue-75904-move-closure-loop.rs:5:1
+   |
+LL | struct NotCopy;
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr
index 17f48f5f7bf..e6bf52276ac 100644
--- a/tests/ui/moves/move-fn-self-receiver.stderr
+++ b/tests/ui/moves/move-fn-self-receiver.stderr
@@ -101,6 +101,12 @@ LL |     mut_foo;
    |     ^^^^^^^ move out of `mut_foo` occurs here
 LL |     ret;
    |     --- borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/move-fn-self-receiver.rs:5:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^
 
 error[E0382]: use of moved value: `rc_foo`
   --> $DIR/move-fn-self-receiver.rs:55:5
@@ -132,6 +138,11 @@ LL |     foo_add + Foo;
 LL |     foo_add;
    |     ^^^^^^^ value used here after move
    |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/move-fn-self-receiver.rs:5:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 
diff --git a/tests/ui/moves/move-into-dead-array-1.stderr b/tests/ui/moves/move-into-dead-array-1.stderr
index 83779fb16ed..d9b719730d6 100644
--- a/tests/ui/moves/move-into-dead-array-1.stderr
+++ b/tests/ui/moves/move-into-dead-array-1.stderr
@@ -8,8 +8,8 @@ LL |     a[i] = d();
    |
 help: consider assigning a value
    |
-LL |     let mut a: [D; 4] = todo!();
-   |                       +++++++++
+LL |     let mut a: [D; 4] = [value; 4];
+   |                       ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/move-of-addr-of-mut.stderr b/tests/ui/moves/move-of-addr-of-mut.stderr
index 706b52d3402..46f7d39a61a 100644
--- a/tests/ui/moves/move-of-addr-of-mut.stderr
+++ b/tests/ui/moves/move-of-addr-of-mut.stderr
@@ -9,8 +9,8 @@ LL |     std::ptr::addr_of_mut!(x);
    = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let mut x: S = todo!();
-   |                  +++++++++
+LL |     let mut x: S = value;
+   |                  +++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr
index aa0251dbd85..9e4a08e0cef 100644
--- a/tests/ui/moves/move-out-of-array-1.stderr
+++ b/tests/ui/moves/move-out-of-array-1.stderr
@@ -6,6 +6,12 @@ LL |     a[i]
    |     |
    |     cannot move out of here
    |     move occurs because `a[_]` has type `D`, which does not implement the `Copy` trait
+   |
+note: if `D` implemented `Clone`, you could clone the value
+  --> $DIR/move-out-of-array-1.rs:5:1
+   |
+LL | struct D { _x: u8 }
+   | ^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs b/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs
index b2f68352f89..9d7277c1c24 100644
--- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs
+++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs
@@ -2,7 +2,7 @@ use std::thread;
 
 fn main() {
     let x = "Hello world!".to_string();
-    thread::spawn(move|| {
+    thread::spawn(move || {
         println!("{}", x);
     });
     println!("{}", x); //~ ERROR borrow of moved value
diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr
index 5e527bf445e..c2b9aeab237 100644
--- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr
+++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr
@@ -3,8 +3,8 @@ error[E0382]: borrow of moved value: `x`
    |
 LL |     let x = "Hello world!".to_string();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
-LL |     thread::spawn(move|| {
-   |                   ------ value moved into closure here
+LL |     thread::spawn(move || {
+   |                   ------- value moved into closure here
 LL |         println!("{}", x);
    |                        - variable moved due to use in closure
 LL |     });
diff --git a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
index 513631b2060..523134a9425 100644
--- a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
+++ b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
@@ -7,6 +7,11 @@ LL |     let _f = to_fn(|| test(i));
    |                    --      ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
    |                    |
    |                    captured by this `Fn` closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _f = to_fn(|| test(i.clone()));
+   |                             ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/needs-clone-through-deref.fixed b/tests/ui/moves/needs-clone-through-deref.fixed
index 43ea15d1b63..8b201c4720d 100644
--- a/tests/ui/moves/needs-clone-through-deref.fixed
+++ b/tests/ui/moves/needs-clone-through-deref.fixed
@@ -12,7 +12,7 @@ impl Deref for S {
 impl S {
     fn foo(&self) {
         // `self.clone()` returns `&S`, not `Vec`
-        for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} //~ ERROR cannot move out of dereference of `S`
+        for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {} //~ ERROR cannot move out of dereference of `S`
     }
 }
 fn main() {}
diff --git a/tests/ui/moves/needs-clone-through-deref.stderr b/tests/ui/moves/needs-clone-through-deref.stderr
index ff92f32e8d2..1f9aefeb4dd 100644
--- a/tests/ui/moves/needs-clone-through-deref.stderr
+++ b/tests/ui/moves/needs-clone-through-deref.stderr
@@ -10,8 +10,8 @@ note: `into_iter` takes ownership of the receiver `self`, which moves value
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
 help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
-LL |         for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {}
-   |                  ++++++++++++++++++++++++++++++            +
+LL |         for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {}
+   |                  ++++++++++++++++++++++++++++++    ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed
index b3eae0b22b6..cdc86f61d24 100644
--- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed
+++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed
@@ -18,7 +18,7 @@ pub fn hashmap_copy<T, U>(
     map: &HashMap<T, U, Hash128_1>,
 ) where T: Hash + Clone, U: Clone
 {
-    let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); //~ ERROR
+    let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect(); //~ ERROR
 }
 
 pub fn make_map() -> HashMap<String, i64, Hash128_1>
diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
index 403daf8ff7c..755bbc5c21b 100644
--- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
+++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr
@@ -10,8 +10,8 @@ note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`,
   --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
 help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
    |
-LL |     let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
-   |                            ++++++++++++++++++++++++++++++++++++++++++++           +
+LL |     let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect();
+   |                            ++++++++++++++++++++++++++++++++++++++++++++   ~
 help: consider annotating `Hash128_1` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/moves/suggest-clone.fixed b/tests/ui/moves/suggest-clone.fixed
index 59276a7b96d..59a162e72c1 100644
--- a/tests/ui/moves/suggest-clone.fixed
+++ b/tests/ui/moves/suggest-clone.fixed
@@ -7,5 +7,5 @@ impl Foo {
 }
 fn main() {
     let foo = &Foo;
-    <Foo as Clone>::clone(&foo).foo(); //~ ERROR cannot move out
+    <Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
 }
diff --git a/tests/ui/moves/suggest-clone.stderr b/tests/ui/moves/suggest-clone.stderr
index 25e89a58955..f8e0ccdfcef 100644
--- a/tests/ui/moves/suggest-clone.stderr
+++ b/tests/ui/moves/suggest-clone.stderr
@@ -15,6 +15,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |     <Foo as Clone>::clone(&foo).foo();
    |     +++++++++++++++++++++++   +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     foo.clone().foo();
+   |        ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index bab47064f6c..02cb9cb22a3 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -36,7 +36,7 @@ error[E0308]: mismatched types
 LL |     [(); loop { break }];
    |                 ^^^^^ expected `usize`, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |     [(); loop { break 42 }];
    |                       ++
diff --git a/tests/ui/nll/cannot-move-block-spans.stderr b/tests/ui/nll/cannot-move-block-spans.stderr
index 0dc5c08ea5f..d96773e1edf 100644
--- a/tests/ui/nll/cannot-move-block-spans.stderr
+++ b/tests/ui/nll/cannot-move-block-spans.stderr
@@ -9,6 +9,11 @@ help: consider removing the dereference here
 LL -     let x = { *r };
 LL +     let x = { r };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let x = { *r };
+LL +     let x = { r.clone() };
+   |
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:6:22
@@ -21,6 +26,11 @@ help: consider removing the dereference here
 LL -     let y = unsafe { *r };
 LL +     let y = unsafe { r };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = unsafe { *r };
+LL +     let y = unsafe { r.clone() };
+   |
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:7:26
@@ -33,6 +43,11 @@ help: consider removing the dereference here
 LL -     let z = loop { break *r; };
 LL +     let z = loop { break r; };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let z = loop { break *r; };
+LL +     let z = loop { break r.clone(); };
+   |
 
 error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:11:15
@@ -47,6 +62,10 @@ help: consider borrowing here
    |
 LL |     let x = { &arr[0] };
    |               +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let x = { arr[0].clone() };
+   |                     ++++++++
 
 error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:12:22
@@ -61,6 +80,10 @@ help: consider borrowing here
    |
 LL |     let y = unsafe { &arr[0] };
    |                      +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = unsafe { arr[0].clone() };
+   |                            ++++++++
 
 error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:13:26
@@ -75,6 +98,10 @@ help: consider borrowing here
    |
 LL |     let z = loop { break &arr[0]; };
    |                          +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let z = loop { break arr[0].clone(); };
+   |                                ++++++++
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:17:38
@@ -87,6 +114,11 @@ help: consider removing the dereference here
 LL -     let x = { let mut u = 0; u += 1; *r };
 LL +     let x = { let mut u = 0; u += 1; r };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let x = { let mut u = 0; u += 1; *r };
+LL +     let x = { let mut u = 0; u += 1; r.clone() };
+   |
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:18:45
@@ -99,6 +131,11 @@ help: consider removing the dereference here
 LL -     let y = unsafe { let mut u = 0; u += 1; *r };
 LL +     let y = unsafe { let mut u = 0; u += 1; r };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = unsafe { let mut u = 0; u += 1; *r };
+LL +     let y = unsafe { let mut u = 0; u += 1; r.clone() };
+   |
 
 error[E0507]: cannot move out of `*r` which is behind a shared reference
   --> $DIR/cannot-move-block-spans.rs:19:49
@@ -111,6 +148,11 @@ help: consider removing the dereference here
 LL -     let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
 LL +     let z = loop { let mut u = 0; u += 1; break r; u += 2; };
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
+LL +     let z = loop { let mut u = 0; u += 1; break r.clone(); u += 2; };
+   |
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/nll/closure-access-spans.stderr b/tests/ui/nll/closure-access-spans.stderr
index 3e98fbd5e1d..f789e5e9f95 100644
--- a/tests/ui/nll/closure-access-spans.stderr
+++ b/tests/ui/nll/closure-access-spans.stderr
@@ -57,6 +57,12 @@ LL |     || x;
    |     move out of `x` occurs here
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let r = &x;
+LL +     let r = x.clone();
+   |
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:35:5
@@ -103,6 +109,11 @@ LL |     || *x = String::new();
    |     ^^ -- borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/closure-access-spans.rs:50:5
@@ -115,6 +126,11 @@ LL |     || x;
    |     ^^ - use occurs due to use in closure
    |     |
    |     value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/nll/closure-move-spans.fixed b/tests/ui/nll/closure-move-spans.fixed
new file mode 100644
index 00000000000..edd74e434e0
--- /dev/null
+++ b/tests/ui/nll/closure-move-spans.fixed
@@ -0,0 +1,23 @@
+// check that moves due to a closure capture give a special note
+//@ run-rustfix
+#![allow(unused_variables, unused_must_use, dead_code)]
+
+fn move_after_move(x: String) {
+    || x.clone();
+    let y = x; //~ ERROR
+}
+
+fn borrow_after_move(x: String) {
+    || x.clone();
+    let y = &x; //~ ERROR
+}
+
+fn borrow_mut_after_move(mut x: String) {
+    || x.clone();
+    let y = &mut x; //~ ERROR
+}
+
+fn fn_ref<F: Fn()>(f: F) -> F { f }
+fn fn_mut<F: FnMut()>(f: F) -> F { f }
+
+fn main() {}
diff --git a/tests/ui/nll/closure-move-spans.rs b/tests/ui/nll/closure-move-spans.rs
index bf2431870a9..bba5c3776e6 100644
--- a/tests/ui/nll/closure-move-spans.rs
+++ b/tests/ui/nll/closure-move-spans.rs
@@ -1,4 +1,6 @@
 // check that moves due to a closure capture give a special note
+//@ run-rustfix
+#![allow(unused_variables, unused_must_use, dead_code)]
 
 fn move_after_move(x: String) {
     || x;
diff --git a/tests/ui/nll/closure-move-spans.stderr b/tests/ui/nll/closure-move-spans.stderr
index 0446ef7b066..0b1da57605c 100644
--- a/tests/ui/nll/closure-move-spans.stderr
+++ b/tests/ui/nll/closure-move-spans.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/closure-move-spans.rs:5:13
+  --> $DIR/closure-move-spans.rs:7:13
    |
 LL | fn move_after_move(x: String) {
    |                    - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -9,9 +9,14 @@ LL |     || x;
    |     value moved into closure here
 LL |     let y = x;
    |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     || x.clone();
+   |         ++++++++
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-move-spans.rs:10:13
+  --> $DIR/closure-move-spans.rs:12:13
    |
 LL | fn borrow_after_move(x: String) {
    |                      - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -21,9 +26,14 @@ LL |     || x;
    |     value moved into closure here
 LL |     let y = &x;
    |             ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     || x.clone();
+   |         ++++++++
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-move-spans.rs:15:13
+  --> $DIR/closure-move-spans.rs:17:13
    |
 LL | fn borrow_mut_after_move(mut x: String) {
    |                          ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -33,6 +43,11 @@ LL |     || x;
    |     value moved into closure here
 LL |     let y = &mut x;
    |             ^^^^^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     || x.clone();
+   |         ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/nll/closures-in-loops.stderr b/tests/ui/nll/closures-in-loops.stderr
index 2c1008c516c..050b220e626 100644
--- a/tests/ui/nll/closures-in-loops.stderr
+++ b/tests/ui/nll/closures-in-loops.stderr
@@ -4,10 +4,16 @@ error[E0382]: use of moved value: `x`
 LL | fn repreated_move(x: String) {
    |                   - move occurs because `x` has type `String`, which does not implement the `Copy` trait
 LL |     for i in 0..10 {
+   |     -------------- inside of this loop
 LL |         || x;
    |         ^^ - use occurs due to use in closure
    |         |
    |         value moved into closure here, in previous iteration of loop
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         || x.clone();
+   |             ++++++++
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/closures-in-loops.rs:13:16
diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
index 97ed414b1ec..2aff375f0a7 100644
--- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -27,6 +27,12 @@ LL |     let mut s: S<B> = S::new(); drop(s);
    |         move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait
 LL |     s.x = 10; s.y = Box::new(20);
    |     ^^^^^^^^ value partially assigned here after move
+   |
+note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
+  --> $DIR/issue-21232-partial-init-and-use.rs:15:1
+   |
+LL | struct S<Y> {
+   | ^^^^^^^^^^^
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-21232-partial-init-and-use.rs:116:5
@@ -72,6 +78,12 @@ LL |     let mut s: S<B> = S::new(); drop(s);
    |         move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait
 LL |     s.x = 10;
    |     ^^^^^^^^ value partially assigned here after move
+   |
+note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
+  --> $DIR/issue-21232-partial-init-and-use.rs:15:1
+   |
+LL | struct S<Y> {
+   | ^^^^^^^^^^^
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-21232-partial-init-and-use.rs:142:5
diff --git a/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr
index ae797800457..39ec45b20ea 100644
--- a/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr
+++ b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr
@@ -10,6 +10,11 @@ LL |         _ if { (|| { let bar = b; *bar = false; })();
    |                 --             - variable moved due to use in closure
    |                 |
    |                 value moved into closure here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ if { (|| { let bar = b.clone(); *bar = false; })();
+   |                                 ++++++++
 
 error[E0382]: use of moved value: `b`
   --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
@@ -23,6 +28,11 @@ LL |             (|| { let bar = b; *bar = false; })();
    |              --             - variable moved due to use in closure
    |              |
    |              value moved into closure here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |             (|| { let bar = b.clone(); *bar = false; })();
+   |                              ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
index 7f9cbc3c30a..f4e7869bf00 100644
--- a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
+++ b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
@@ -41,6 +41,10 @@ help: consider borrowing here
    |
 LL |     let p = &s.url; p
    |             +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p = s.url.clone(); p
+   |                  ++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/nll/issue-52086.stderr b/tests/ui/nll/issue-52086.stderr
index 3b2dae9b72b..e4f0c49e557 100644
--- a/tests/ui/nll/issue-52086.stderr
+++ b/tests/ui/nll/issue-52086.stderr
@@ -3,12 +3,22 @@ error[E0507]: cannot move out of an `Rc`
    |
 LL |     drop(x.field);
    |          ^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.field.clone());
+   |                 ++++++++
 
 error[E0507]: cannot move out of an `Arc`
   --> $DIR/issue-52086.rs:12:10
    |
 LL |     drop(y.field);
    |          ^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(y.field.clone());
+   |                 ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
index 587f3071027..fbaec8a6008 100644
--- a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -7,6 +7,11 @@ LL |        expect_fn(|| drop(x.0));
    |                  --      ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
    |                  |
    |                  captured by this `Fn` closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |        expect_fn(|| drop(x.0.clone()));
+   |                             ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
index d692ded36fa..066e77b17fc 100644
--- a/tests/ui/nll/match-cfg-fake-edges.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -126,8 +126,8 @@ LL |         _ if { x; false } => 2,
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/match-cfg-fake-edges.rs:86:31
@@ -142,8 +142,8 @@ LL |         _ if let Some(()) = { x; None } => 2,
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/match-cfg-fake-edges.rs:99:22
diff --git a/tests/ui/nll/match-on-borrowed.stderr b/tests/ui/nll/match-on-borrowed.stderr
index 9273484565a..4e0b048fb4b 100644
--- a/tests/ui/nll/match-on-borrowed.stderr
+++ b/tests/ui/nll/match-on-borrowed.stderr
@@ -43,8 +43,8 @@ LL |     match n {}
    |
 help: consider assigning a value
    |
-LL |     let n: Never = todo!();
-   |                  +++++++++
+LL |     let n: Never = value;
+   |                  +++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr
index 0d994ef29ba..842ecaf524b 100644
--- a/tests/ui/nll/move-errors.stderr
+++ b/tests/ui/nll/move-errors.stderr
@@ -4,6 +4,11 @@ error[E0507]: cannot move out of `*a` which is behind a shared reference
 LL |     let b = *a;
    |             ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let b = *a;
@@ -19,6 +24,11 @@ LL |     let b = a[0];
    |             cannot move out of here
    |             move occurs because `a[_]` has type `A`, which does not implement the `Copy` trait
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 help: consider borrowing here
    |
 LL |     let b = &a[0];
@@ -30,6 +40,11 @@ error[E0507]: cannot move out of `**r` which is behind a shared reference
 LL |     let s = **r;
    |             ^^^ move occurs because `**r` has type `A`, which does not implement the `Copy` trait
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let s = **r;
@@ -42,6 +57,11 @@ error[E0507]: cannot move out of an `Rc`
 LL |     let s = *r;
    |             ^^ move occurs because value has type `A`, which does not implement the `Copy` trait
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 help: consider removing the dereference here
    |
 LL -     let s = *r;
@@ -57,6 +77,11 @@ LL |     let a = [A("".to_string())][0];
    |             cannot move out of here
    |             move occurs because value has type `A`, which does not implement the `Copy` trait
    |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 help: consider borrowing here
    |
 LL |     let a = &[A("".to_string())][0];
@@ -96,6 +121,12 @@ error[E0507]: cannot move out of `*a` which is behind a shared reference
    |
 LL |     b = *a;
    |         ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait
+   |
+note: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/move-errors.rs:1:1
+   |
+LL | struct A(String);
+   | ^^^^^^^^
 
 error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
   --> $DIR/move-errors.rs:74:11
diff --git a/tests/ui/once-cant-call-twice-on-heap.stderr b/tests/ui/once-cant-call-twice-on-heap.stderr
index 33dd840dbc2..42697374115 100644
--- a/tests/ui/once-cant-call-twice-on-heap.stderr
+++ b/tests/ui/once-cant-call-twice-on-heap.stderr
@@ -8,15 +8,13 @@ LL |     blk();
 LL |     blk();
    |     ^^^ value used here after move
    |
-note: this value implements `FnOnce`, which causes it to be moved when called
-  --> $DIR/once-cant-call-twice-on-heap.rs:7:5
+note: `FnOnce` closures can only be called once
+  --> $DIR/once-cant-call-twice-on-heap.rs:6:10
    |
+LL | fn foo<F:FnOnce()>(blk: F) {
+   |          ^^^^^^^^ `F` is made to be an `FnOnce` closure here
 LL |     blk();
-   |     ^^^
-help: consider further restricting this bound
-   |
-LL | fn foo<F:FnOnce() + Copy>(blk: F) {
-   |                   ++++++
+   |     ----- this value implements `FnOnce`, which causes it to be moved when called
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr
index 8178bd22373..cc21df77353 100644
--- a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr
+++ b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr
@@ -138,7 +138,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/assoc-static-semantic-fail.rs:32:5
    |
 LL |     pub(crate) default static TD: u8;
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -162,7 +162,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/assoc-static-semantic-fail.rs:47:5
    |
 LL |     pub default static TD: u8;
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/parser/default.stderr b/tests/ui/parser/default.stderr
index e6330f368d9..c420e5a774d 100644
--- a/tests/ui/parser/default.stderr
+++ b/tests/ui/parser/default.stderr
@@ -21,7 +21,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/default.rs:17:5
    |
 LL |     pub default fn foo<T: Default>() -> T {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr
index 7c5cc4777b6..2c0baf7e5f8 100644
--- a/tests/ui/parser/recover/recover-range-pats.stderr
+++ b/tests/ui/parser/recover/recover-range-pats.stderr
@@ -491,10 +491,6 @@ LL |     mac2!(0, 1);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variants that aren't matched
-   |
-LL |             if let $e1..$e2; { todo!() }
-   |             ++               +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:138:17
@@ -509,10 +505,6 @@ LL |     mac2!(0, 1);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variants that aren't matched
-   |
-LL |             if let $e1...$e2; { todo!() }
-   |             ++                +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:142:17
@@ -527,10 +519,6 @@ LL |     mac2!(0, 1);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variants that aren't matched
-   |
-LL |             if let $e1..=$e2; { todo!() }
-   |             ++                +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:151:17
@@ -545,10 +533,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let ..$e; { todo!() }
-   |             ++           +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:153:17
@@ -563,10 +547,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let ...$e; { todo!() }
-   |             ++            +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:156:17
@@ -581,10 +561,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let ..=$e; { todo!() }
-   |             ++            +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:158:17
@@ -599,10 +575,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let $e..; { todo!() }
-   |             ++           +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:160:17
@@ -617,10 +589,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let $e...; { todo!() }
-   |             ++            +++++++++++
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/recover-range-pats.rs:162:17
@@ -635,10 +603,6 @@ LL |     mac!(0);
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |             if let $e..=; { todo!() }
-   |             ++            +++++++++++
 
 error: aborting due to 69 previous errors
 
diff --git a/tests/ui/parser/trait-pub-assoc-const.stderr b/tests/ui/parser/trait-pub-assoc-const.stderr
index 436f6a3909c..1bace786b21 100644
--- a/tests/ui/parser/trait-pub-assoc-const.stderr
+++ b/tests/ui/parser/trait-pub-assoc-const.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/trait-pub-assoc-const.rs:2:5
    |
 LL |     pub const Foo: u32;
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/parser/trait-pub-assoc-ty.stderr b/tests/ui/parser/trait-pub-assoc-ty.stderr
index 279e3a95354..28e05bdc630 100644
--- a/tests/ui/parser/trait-pub-assoc-ty.stderr
+++ b/tests/ui/parser/trait-pub-assoc-ty.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/trait-pub-assoc-ty.rs:2:5
    |
 LL |     pub type Foo;
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/parser/trait-pub-method.stderr b/tests/ui/parser/trait-pub-method.stderr
index ee8b6f7cb62..cc1ba0eaaea 100644
--- a/tests/ui/parser/trait-pub-method.stderr
+++ b/tests/ui/parser/trait-pub-method.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/trait-pub-method.rs:2:5
    |
 LL |     pub fn foo();
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 9359244c6eb..00964cb8336 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -333,6 +333,11 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+note: if `U` implemented `Clone`, you could clone the value
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
+   |
+LL |     struct U;
+   |     ^^^^^^^^
 
 error[E0507]: cannot move out of `b` in pattern guard
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
@@ -341,6 +346,11 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+note: if `U` implemented `Clone`, you could clone the value
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
+   |
+LL |     struct U;
+   |     ^^^^^^^^
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0507]: cannot move out of `a` in pattern guard
diff --git a/tests/ui/precondition-checks/cfg-ub-checks-default.rs b/tests/ui/precondition-checks/cfg-ub-checks-default.rs
index 57a19523147..b672589d02a 100644
--- a/tests/ui/precondition-checks/cfg-ub-checks-default.rs
+++ b/tests/ui/precondition-checks/cfg-ub-checks-default.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-//@ revisions YES NO
+//@ revisions: YES NO
 //@ [YES] compile-flags: -Cdebug-assertions=yes
 //@ [NO] compile-flags: -Cdebug-assertions=no
 
diff --git a/tests/ui/privacy/issue-113860-1.stderr b/tests/ui/privacy/issue-113860-1.stderr
index c33ce26f0f6..c05452fb51c 100644
--- a/tests/ui/privacy/issue-113860-1.stderr
+++ b/tests/ui/privacy/issue-113860-1.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-113860-1.rs:12:5
    |
 LL |     pub(self) fn fun() {}
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/privacy/issue-113860-2.stderr b/tests/ui/privacy/issue-113860-2.stderr
index 6748bc27668..c53c490ca1e 100644
--- a/tests/ui/privacy/issue-113860-2.stderr
+++ b/tests/ui/privacy/issue-113860-2.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-113860-2.rs:12:5
    |
 LL |     pub(self) type X = Self;
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/privacy/issue-113860.stderr b/tests/ui/privacy/issue-113860.stderr
index 3204f4ff916..d813b740ac5 100644
--- a/tests/ui/privacy/issue-113860.stderr
+++ b/tests/ui/privacy/issue-113860.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-113860.rs:12:5
    |
 LL |     pub(self) const X: u32 = 3;
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/privacy/issue-29161.stderr b/tests/ui/privacy/issue-29161.stderr
index 1a6c80499a1..f8911cb09c1 100644
--- a/tests/ui/privacy/issue-29161.stderr
+++ b/tests/ui/privacy/issue-29161.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/issue-29161.rs:5:9
    |
 LL |         pub fn default() -> A {
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/privacy/priv-in-bad-locations.stderr b/tests/ui/privacy/priv-in-bad-locations.stderr
index 70dab5bfe13..93a0eabb914 100644
--- a/tests/ui/privacy/priv-in-bad-locations.stderr
+++ b/tests/ui/privacy/priv-in-bad-locations.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/priv-in-bad-locations.rs:1:1
    |
 LL | pub extern "C" {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual foreign items instead
 
@@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/priv-in-bad-locations.rs:11:1
    |
 LL | pub impl B {}
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual impl items instead
 
@@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/priv-in-bad-locations.rs:13:1
    |
 LL | pub impl A for B {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -26,7 +26,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/priv-in-bad-locations.rs:14:5
    |
 LL |     pub fn foo(&self) {}
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
diff --git a/tests/ui/privacy/privacy-sanity.stderr b/tests/ui/privacy/privacy-sanity.stderr
index a537f8c1901..0acb05cbaba 100644
--- a/tests/ui/privacy/privacy-sanity.stderr
+++ b/tests/ui/privacy/privacy-sanity.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:13:1
    |
 LL | pub impl Tr for S {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:14:5
    |
 LL |     pub fn f() {}
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:15:5
    |
 LL |     pub const C: u8 = 0;
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -26,7 +26,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:16:5
    |
 LL |     pub type T = u8;
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -34,7 +34,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:18:1
    |
 LL | pub impl S {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual impl items instead
 
@@ -42,7 +42,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:23:1
    |
 LL | pub extern "C" {
-   | ^^^
+   | ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual foreign items instead
 
@@ -50,7 +50,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:39:5
    |
 LL |     pub impl Tr for S {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -58,7 +58,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:40:9
    |
 LL |         pub fn f() {}
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -66,7 +66,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:41:9
    |
 LL |         pub const C: u8 = 0;
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -74,7 +74,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:42:9
    |
 LL |         pub type T = u8;
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -82,7 +82,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:44:5
    |
 LL |     pub impl S {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual impl items instead
 
@@ -90,7 +90,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:49:5
    |
 LL |     pub extern "C" {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual foreign items instead
 
@@ -98,7 +98,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:68:5
    |
 LL |     pub impl Tr for S {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -106,7 +106,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:69:9
    |
 LL |         pub fn f() {}
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -114,7 +114,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:70:9
    |
 LL |         pub const C: u8 = 0;
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -122,7 +122,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:71:9
    |
 LL |         pub type T = u8;
-   |         ^^^
+   |         ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -130,7 +130,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:73:5
    |
 LL |     pub impl S {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual impl items instead
 
@@ -138,7 +138,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/privacy-sanity.rs:78:5
    |
 LL |     pub extern "C" {
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: place qualifiers on individual foreign items instead
 
diff --git a/tests/ui/privacy/useless-pub.stderr b/tests/ui/privacy/useless-pub.stderr
index 73497e3fed5..7d064c12a09 100644
--- a/tests/ui/privacy/useless-pub.stderr
+++ b/tests/ui/privacy/useless-pub.stderr
@@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/useless-pub.rs:8:5
    |
 LL |     pub fn foo(&self) {}
-   |     ^^^
+   |     ^^^ help: remove the qualifier
    |
    = note: trait items always share the visibility of their trait
 
@@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/useless-pub.rs:12:10
    |
 LL |     V1 { pub f: i32 },
-   |          ^^^
+   |          ^^^ help: remove the qualifier
    |
    = note: enum variants and their fields always share the visibility of the enum they are in
 
@@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here
   --> $DIR/useless-pub.rs:13:8
    |
 LL |     V2(pub i32),
-   |        ^^^
+   |        ^^^ help: remove the qualifier
    |
    = note: enum variants and their fields always share the visibility of the enum they are in
 
diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
index a749361bf30..0ab70c5ae8a 100644
--- a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
+++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
@@ -5,6 +5,10 @@ LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         VecWrapper::A(v) if { drop(v.clone()); false } => 1,
+   |                                     ++++++++
 
 error[E0507]: cannot move out of `v` in pattern guard
   --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
@@ -13,6 +17,10 @@ LL |         VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
    |                                                   ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         VecWrapper::A(v) if let Some(()) = { drop(v.clone()); None } => 1,
+   |                                                    ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
index 9285492b224..c261f994283 100644
--- a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
+++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
@@ -5,6 +5,10 @@ LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         A { a: v } if { drop(v.clone()); true } => v,
+   |                               ++++++++
 
 error[E0507]: cannot move out of `v` in pattern guard
   --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
@@ -13,6 +17,10 @@ LL |         A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
    |                                             ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         A { a: v } if let Some(()) = { drop(v.clone()); Some(()) } => v,
+   |                                              ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index 29a606c4f01..f37dc320fa3 100644
--- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -43,6 +43,11 @@ LL |     f(Box::new(|a| {
 LL |
 LL |         foo(f);
    |             ^ move occurs because `f` has type `{closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58}`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         foo(f.clone());
+   |              ++++++++
 
 error[E0505]: cannot move out of `f` because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16
@@ -57,6 +62,11 @@ LL |     f(Box::new(|a| {
 LL |
 LL |         foo(f);
    |             - move occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     f.clone()(Box::new(|a| {
+   |      ++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/span/send-is-not-static-std-sync.stderr b/tests/ui/span/send-is-not-static-std-sync.stderr
index 46534b39168..50b8ffe0114 100644
--- a/tests/ui/span/send-is-not-static-std-sync.stderr
+++ b/tests/ui/span/send-is-not-static-std-sync.stderr
@@ -11,6 +11,12 @@ LL |     drop(y);
 ...
 LL |         *lock.lock().unwrap() = &z;
    |          ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *lock.lock().unwrap() = &*y;
+LL +     *lock.lock().unwrap() = y.clone();
+   |
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:16:33
@@ -38,6 +44,12 @@ LL |     drop(y);
 ...
 LL |         *lock.write().unwrap() = &z;
    |          ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *lock.write().unwrap() = &*y;
+LL +     *lock.write().unwrap() = y.clone();
+   |
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:30:34
@@ -65,6 +77,12 @@ LL |     drop(y);
 ...
 LL |         tx.send(&z).unwrap();
    |         -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     tx.send(&*y);
+LL +     tx.send(y.clone());
+   |
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:46:17
diff --git a/tests/ui/suggestions/borrow-for-loop-head.stderr b/tests/ui/suggestions/borrow-for-loop-head.stderr
index 0f179438a12..a8de9986c31 100644
--- a/tests/ui/suggestions/borrow-for-loop-head.stderr
+++ b/tests/ui/suggestions/borrow-for-loop-head.stderr
@@ -7,6 +7,12 @@ LL |     for i in &a {
    |              -- borrow of `a` occurs here
 LL |         for j in a {
    |                  ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     for i in &a {
+LL +     for i in a.clone() {
+   |
 
 error[E0382]: use of moved value: `a`
   --> $DIR/borrow-for-loop-head.rs:4:18
diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr
index b27d9aef066..bfcc2307fd7 100644
--- a/tests/ui/suggestions/deref-path-method.stderr
+++ b/tests/ui/suggestions/deref-path-method.stderr
@@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll
       Vec::<T>::with_capacity
       Vec::<T>::try_with_capacity
       Vec::<T>::from_raw_parts
-      and 4 others
+      and 6 others
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 help: the function `contains` is implemented on `[_]`
    |
diff --git a/tests/ui/suggestions/for-i-in-vec.fixed b/tests/ui/suggestions/for-i-in-vec.fixed
index f266e80bcfa..17ae6fb5ab7 100644
--- a/tests/ui/suggestions/for-i-in-vec.fixed
+++ b/tests/ui/suggestions/for-i-in-vec.fixed
@@ -8,9 +8,9 @@ struct Foo {
 
 impl Foo {
     fn bar(&self) {
-        for _ in &self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference
+        for _ in &self.v.clone() { //~ ERROR cannot move out of `self.v` which is behind a shared reference
         }
-        for _ in &self.h { //~ ERROR cannot move out of `self.h` which is behind a shared reference
+        for _ in &self.h.clone() { //~ ERROR cannot move out of `self.h` which is behind a shared reference
         }
     }
 }
@@ -18,7 +18,7 @@ impl Foo {
 const LOADERS: &Vec<&'static u8> = &Vec::new();
 
 pub fn break_code() -> Option<&'static u8> {
-    for loader in &*LOADERS { //~ ERROR cannot move out of a shared reference
+    for loader in &LOADERS.clone() { //~ ERROR cannot move out of a shared reference
         return Some(loader);
     }
     None
diff --git a/tests/ui/suggestions/for-i-in-vec.stderr b/tests/ui/suggestions/for-i-in-vec.stderr
index c5b81e6b871..64eb4f8bd23 100644
--- a/tests/ui/suggestions/for-i-in-vec.stderr
+++ b/tests/ui/suggestions/for-i-in-vec.stderr
@@ -13,6 +13,10 @@ help: consider iterating over a slice of the `Vec<u32>`'s content to avoid movin
    |
 LL |         for _ in &self.v {
    |                  +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         for _ in self.v.clone() {
+   |                        ++++++++
 
 error[E0507]: cannot move out of `self.h` which is behind a shared reference
   --> $DIR/for-i-in-vec.rs:13:18
@@ -27,6 +31,10 @@ help: consider iterating over a slice of the `HashMap<i32, i32>`'s content to av
    |
 LL |         for _ in &self.h {
    |                  +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         for _ in self.h.clone() {
+   |                        ++++++++
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/for-i-in-vec.rs:21:19
@@ -43,6 +51,11 @@ help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid movin
    |
 LL |     for loader in &*LOADERS {
    |                   +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     for loader in *LOADERS {
+LL +     for loader in LOADERS.clone() {
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/suggestions/issue-68049-1.stderr b/tests/ui/suggestions/issue-68049-1.stderr
index 760f83d548f..4e683b75c48 100644
--- a/tests/ui/suggestions/issue-68049-1.stderr
+++ b/tests/ui/suggestions/issue-68049-1.stderr
@@ -1,6 +1,8 @@
 error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
   --> $DIR/issue-68049-1.rs:7:9
    |
+LL |     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+   |                     ----- this is an immutable reference
 LL |         self.0 += 1;
    |         ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
 
diff --git a/tests/ui/suggestions/issue-68049-2.rs b/tests/ui/suggestions/issue-68049-2.rs
index 1c3430c14e9..496a1299dcf 100644
--- a/tests/ui/suggestions/issue-68049-2.rs
+++ b/tests/ui/suggestions/issue-68049-2.rs
@@ -1,11 +1,11 @@
 trait Hello {
-  fn example(&self, input: &i32); // should suggest here
+  fn example(&self, input: &i32);
 }
 
 struct Test1(i32);
 
 impl Hello for Test1 {
-  fn example(&self, input: &i32) { // should not suggest here
+  fn example(&self, input: &i32) {
       *input = self.0; //~ ERROR cannot assign
   }
 }
@@ -13,7 +13,7 @@ impl Hello for Test1 {
 struct Test2(i32);
 
 impl Hello for Test2 {
-  fn example(&self, input: &i32) { // should not suggest here
+  fn example(&self, input: &i32) {
     self.0 += *input; //~ ERROR cannot assign
   }
 }
diff --git a/tests/ui/suggestions/issue-68049-2.stderr b/tests/ui/suggestions/issue-68049-2.stderr
index 6f3c78443f8..449ecabeb7f 100644
--- a/tests/ui/suggestions/issue-68049-2.stderr
+++ b/tests/ui/suggestions/issue-68049-2.stderr
@@ -4,9 +4,9 @@ error[E0594]: cannot assign to `*input`, which is behind a `&` reference
 LL |       *input = self.0;
    |       ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
    |
-help: consider changing this to be a mutable reference
+help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
    |
-LL |   fn example(&self, input: &mut i32) { // should not suggest here
+LL |   fn example(&self, input: &mut i32) {
    |                             +++
 
 error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
@@ -15,10 +15,14 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
 LL |     self.0 += *input;
    |     ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
    |
-help: consider changing this to be a mutable reference
+help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
+   |
+LL ~   fn example(&mut self, input: &i32);
+LL | }
+ ...
+LL | impl Hello for Test2 {
+LL ~   fn example(&mut self, input: &i32) {
    |
-LL |   fn example(&mut self, input: &i32); // should suggest here
-   |              ~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed
index fbed486cef7..4a5a9483c20 100644
--- a/tests/ui/suggestions/option-content-move.fixed
+++ b/tests/ui/suggestions/option-content-move.fixed
@@ -7,7 +7,7 @@ impl LipogramCorpora {
     pub fn validate_all(&mut self) -> Result<(), char> {
         for selection in &self.selections {
             if selection.1.is_some() {
-                if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
+                if <Option<String> as Clone>::clone(&selection.1.clone()).unwrap().contains(selection.0) {
                 //~^ ERROR cannot move out of `selection.1`
                     return Err(selection.0);
                 }
@@ -25,7 +25,7 @@ impl LipogramCorpora2 {
     pub fn validate_all(&mut self) -> Result<(), char> {
         for selection in &self.selections {
             if selection.1.is_ok() {
-                if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
+                if <Result<String, String> as Clone>::clone(&selection.1.clone()).unwrap().contains(selection.0) {
                 //~^ ERROR cannot move out of `selection.1`
                     return Err(selection.0);
                 }
diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr
index e5de150275d..a382a04344a 100644
--- a/tests/ui/suggestions/option-content-move.stderr
+++ b/tests/ui/suggestions/option-content-move.stderr
@@ -13,6 +13,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |                 if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
    |                    ++++++++++++++++++++++++++++++++++           +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |                 if selection.1.clone().unwrap().contains(selection.0) {
+   |                               ++++++++
 
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
   --> $DIR/option-content-move.rs:28:20
@@ -29,6 +33,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
    |
 LL |                 if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
    |                    ++++++++++++++++++++++++++++++++++++++++++           +
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |                 if selection.1.clone().unwrap().contains(selection.0) {
+   |                               ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/return-closures.stderr b/tests/ui/suggestions/return-closures.stderr
index 97c13200ac3..ef1f50b8a6c 100644
--- a/tests/ui/suggestions/return-closures.stderr
+++ b/tests/ui/suggestions/return-closures.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/return-closures.rs:3:5
    |
 LL | fn foo() {
-   |         - help: try adding a return type: `-> impl for<'a> Fn(&'a i32) -> i32`
+   |         - help: try adding a return type: `-> impl FnOnce(&i32) -> i32`
 LL |
 LL |     |x: &i32| 1i32
    |     ^^^^^^^^^^^^^^ expected `()`, found closure
diff --git a/tests/ui/traits/copy-guessing.rs b/tests/ui/traits/copy-guessing.rs
index af25010e3bd..0ffa8249789 100644
--- a/tests/ui/traits/copy-guessing.rs
+++ b/tests/ui/traits/copy-guessing.rs
@@ -18,7 +18,7 @@ fn assert_impls_fn<R,T: Fn()->R>(_: &T){}
 
 fn main() {
     let n = None;
-    //~^ ERROR type annotations needed for `Option<T>`
+    //~^ ERROR type annotations needed for `Option<_>`
     let e = S(&n);
     let f = || {
         // S being copy is critical for this to work
diff --git a/tests/ui/traits/copy-guessing.stderr b/tests/ui/traits/copy-guessing.stderr
index 750140c017c..cae91579ee0 100644
--- a/tests/ui/traits/copy-guessing.stderr
+++ b/tests/ui/traits/copy-guessing.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Option<T>`
+error[E0282]: type annotations needed for `Option<_>`
   --> $DIR/copy-guessing.rs:20:9
    |
 LL |     let n = None;
diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr
index 5be8d2f4b32..0f4b3c3c877 100644
--- a/tests/ui/traits/issue-77982.stderr
+++ b/tests/ui/traits/issue-77982.stderr
@@ -55,7 +55,7 @@ help: try using a fully qualified path to specify the expected types
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
    |                                                      +++++++++++++++++++++++    ~
 
-error[E0283]: type annotations needed for `Box<T>`
+error[E0283]: type annotations needed for `Box<_>`
   --> $DIR/issue-77982.rs:37:9
    |
 LL |     let _ = ().foo();
@@ -73,7 +73,7 @@ help: consider giving this pattern a type, where the type for type parameter `T`
 LL |     let _: Box<T> = ().foo();
    |          ++++++++
 
-error[E0283]: type annotations needed for `Box<T>`
+error[E0283]: type annotations needed for `Box<_>`
   --> $DIR/issue-77982.rs:41:9
    |
 LL |     let _ = (&()).bar();
diff --git a/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr b/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr
index e48d48a7271..4efb883ac74 100644
--- a/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr
+++ b/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr
@@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*t` which is behind a shared reference
    |
 LL |     *t
    |     ^^ move occurs because `*t` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     *t
+LL +     t.clone()
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/try-block/try-block-bad-lifetime.stderr b/tests/ui/try-block/try-block-bad-lifetime.stderr
index 28941cb0a9e..6f693295357 100644
--- a/tests/ui/try-block/try-block-bad-lifetime.stderr
+++ b/tests/ui/try-block/try-block-bad-lifetime.stderr
@@ -34,6 +34,11 @@ LL |             Err(k) ?;
 ...
 LL |         ::std::mem::drop(k);
    |                          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |             Err(k.clone()) ?;
+   |                  ++++++++
 
 error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-bad-lifetime.rs:32:9
diff --git a/tests/ui/type-inference/or_else-multiple-type-params.stderr b/tests/ui/type-inference/or_else-multiple-type-params.stderr
index d1bbe308ed3..3176a2d490e 100644
--- a/tests/ui/type-inference/or_else-multiple-type-params.stderr
+++ b/tests/ui/type-inference/or_else-multiple-type-params.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Result<Child, F>`
+error[E0282]: type annotations needed for `Result<Child, _>`
   --> $DIR/or_else-multiple-type-params.rs:7:18
    |
 LL |         .or_else(|err| {
diff --git a/tests/ui/type/type-error-break-tail.stderr b/tests/ui/type/type-error-break-tail.stderr
index 5ef522fee2a..81f8f52428d 100644
--- a/tests/ui/type/type-error-break-tail.stderr
+++ b/tests/ui/type/type-error-break-tail.stderr
@@ -8,7 +8,7 @@ LL |     loop {
 LL |         if false { break; }
    |                    ^^^^^ expected `i32`, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         if false { break 42; }
    |                          ++
diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed
deleted file mode 100644
index dcb256de18f..00000000000
--- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed
+++ /dev/null
@@ -1,37 +0,0 @@
-//@ run-rustfix
-#![allow(dead_code)]
-
-// https://github.com/rust-lang/rust/issues/112007
-fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
-    if true {
-        writeln!(w, "`;?` here ->")?;
-    } else {
-        return writeln!(w, "but not here");
-        //~^ ERROR mismatched types
-    };
-    Ok(())
-}
-
-macro_rules! baz {
-    ($w: expr) => {
-        bar!($w)
-    }
-}
-
-macro_rules! bar {
-    ($w: expr) => {
-        writeln!($w, "but not here")
-        //~^ ERROR mismatched types
-    }
-}
-
-fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
-    if true {
-        writeln!(w, "`;?` here ->")?;
-    } else {
-        return baz!(w);
-    };
-    Ok(())
-}
-
-fn main() {}
diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs
index 58cd6cbf20c..7ec9f0d4cdb 100644
--- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs
+++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs
@@ -1,8 +1,16 @@
-//@ run-rustfix
-#![allow(dead_code)]
+// Check that we don't leak stdlib implementation details through suggestions.
+// Also check that the suggestion provided tries as hard as it can to see through local macros.
+//
+// FIXME(jieyouxu): this test is NOT run-rustfix because this test contains conflicting
+// MaybeIncorrect suggestions:
+//
+// 1. `return ... ;`
+// 2. `?`
+//
+// when the suggestions are applied to the same file, it becomes uncompilable.
 
 // https://github.com/rust-lang/rust/issues/112007
-fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
+pub fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
     if true {
         writeln!(w, "`;?` here ->")?;
     } else {
@@ -25,7 +33,7 @@ macro_rules! bar {
     }
 }
 
-fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
+pub fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
     if true {
         writeln!(w, "`;?` here ->")?;
     } else {
@@ -34,4 +42,4 @@ fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
     Ok(())
 }
 
-fn main() {}
+pub fn main() {}
diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr
index df2e06e8f3b..889d2c94d0c 100644
--- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr
+++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9
+  --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:17:9
    |
 LL | /     if true {
 LL | |         writeln!(w, "`;?` here ->")?;
@@ -21,9 +21,13 @@ help: you might have meant to return this value
    |
 LL |         return writeln!(w, "but not here");
    |         ++++++                            +
+help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller
+   |
+LL |         writeln!(w, "but not here")?
+   |                                    +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9
+  --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:40:9
    |
 LL | /     if true {
 LL | |         writeln!(w, "`;?` here ->")?;
@@ -44,6 +48,10 @@ help: you might have meant to return this value
    |
 LL |         return baz!(w);
    |         ++++++        +
+help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller
+   |
+LL |         writeln!($w, "but not here")?
+   |                                     +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.rs b/tests/ui/typeck/question-mark-operator-suggestion-span.rs
new file mode 100644
index 00000000000..7aea6e63dd1
--- /dev/null
+++ b/tests/ui/typeck/question-mark-operator-suggestion-span.rs
@@ -0,0 +1,22 @@
+// Check that we don't construct a span for `?` suggestions that point into non-local macros
+// like into the stdlib where the user has no control over.
+//
+// FIXME(jieyouxu): this test is currently NOT run-rustfix because there are conflicting
+// MaybeIncorrect suggestions:
+//
+// 1. adding `return ... ;`, and
+// 2. adding `?`.
+//
+// When rustfix puts those together, the fixed file now contains uncompilable code.
+
+#![crate_type = "lib"]
+
+pub fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
+    if true {
+        writeln!(w, "`;?` here ->")?;
+    } else {
+        writeln!(w, "but not here")
+        //~^ ERROR mismatched types
+    }
+    Ok(())
+}
diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.stderr b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr
new file mode 100644
index 00000000000..089b3bcd198
--- /dev/null
+++ b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr
@@ -0,0 +1,31 @@
+error[E0308]: mismatched types
+  --> $DIR/question-mark-operator-suggestion-span.rs:18:9
+   |
+LL | /     if true {
+LL | |         writeln!(w, "`;?` here ->")?;
+LL | |     } else {
+LL | |         writeln!(w, "but not here")
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>`
+LL | |
+LL | |     }
+   | |_____- expected this to be `()`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<(), std::fmt::Error>`
+   = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using a semicolon here
+   |
+LL |     };
+   |      +
+help: you might have meant to return this value
+   |
+LL |         return writeln!(w, "but not here");
+   |         ++++++                            +
+help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller
+   |
+LL |         writeln!(w, "but not here")?
+   |                                    +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/return_type_containing_closure.rs b/tests/ui/typeck/return_type_containing_closure.rs
index 8b826daeede..b81cac0a58a 100644
--- a/tests/ui/typeck/return_type_containing_closure.rs
+++ b/tests/ui/typeck/return_type_containing_closure.rs
@@ -1,5 +1,5 @@
 #[allow(unused)]
-fn foo() { //~ HELP a return type might be missing here
+fn foo() { //~ HELP try adding a return type
     vec!['a'].iter().map(|c| c)
     //~^ ERROR mismatched types [E0308]
     //~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>`
diff --git a/tests/ui/typeck/return_type_containing_closure.stderr b/tests/ui/typeck/return_type_containing_closure.stderr
index ea9c74be362..3f14650a82c 100644
--- a/tests/ui/typeck/return_type_containing_closure.stderr
+++ b/tests/ui/typeck/return_type_containing_closure.stderr
@@ -10,10 +10,10 @@ help: consider using a semicolon here
    |
 LL |     vec!['a'].iter().map(|c| c);
    |                                +
-help: a return type might be missing here
+help: try adding a return type
    |
-LL | fn foo() -> _ {
-   |          ++++
+LL | fn foo() -> impl Iterator<Item = &char> {
+   |          ++++++++++++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr
index 9cfeb7a5d09..e466f94d0d8 100644
--- a/tests/ui/ufcs/bad-builder.stderr
+++ b/tests/ui/ufcs/bad-builder.stderr
@@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<Q>` consider using one of the followi
       Vec::<T>::with_capacity
       Vec::<T>::try_with_capacity
       Vec::<T>::from_raw_parts
-      and 4 others
+      and 6 others
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 help: there is an associated function `new` with a similar name
    |
diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
index bfa3061de08..cf4391311d0 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
@@ -7,6 +7,11 @@ LL |         let f = to_fn(|| drop(x));
    |                       --      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
    |                       |
    |                       captured by this `Fn` closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let f = to_fn(|| drop(x.clone()));
+   |                                ++++++++
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:19:35
@@ -17,6 +22,11 @@ LL |         let f = to_fn_mut(|| drop(x));
    |                           --      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
    |                           |
    |                           captured by this `FnMut` closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let f = to_fn_mut(|| drop(x.clone()));
+   |                                    ++++++++
 
 error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
   --> $DIR/unboxed-closure-illegal-move.rs:28:36
diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
index 5a76ef3e875..058dbb1e220 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `Option<T>`
+error[E0282]: type annotations needed for `Option<_>`
   --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9
    |
 LL |     let mut closure0 = None;
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed
new file mode 100644
index 00000000000..76f4251daef
--- /dev/null
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed
@@ -0,0 +1,31 @@
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+//@ run-rustfix
+#![allow(unreachable_code, unused_variables)]
+
+pub mod widget {
+    enum Unimplemented {}
+    pub struct Widget(Unimplemented);
+
+    impl Widget {
+        pub fn new() -> Widget {
+            todo!();
+        }
+    }
+
+    pub fn f() {
+        let x: &mut u32;
+        Widget::new();
+        // Ok. Widget type returned from new is known to be uninhabited
+        // and the following code is considered unreachable.
+        *x = 1;
+    }
+}
+
+fn main() {
+    let y: &mut u32 = &mut 42;
+    widget::Widget::new();
+    // Error. Widget type is not known to be uninhabited here,
+    // so the following code is considered reachable.
+    *y = 2; //~ ERROR E0381
+}
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
index 2764bb563d3..1eec57ae046 100644
--- a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
@@ -1,5 +1,7 @@
 // Verifies that MIR building for a call expression respects
 // privacy when checking if a call return type is uninhabited.
+//@ run-rustfix
+#![allow(unreachable_code, unused_variables)]
 
 pub mod widget {
     enum Unimplemented {}
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
index 5f2f02c99fb..9d0771ad79e 100644
--- a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `y` isn't initialized
-  --> $DIR/privately-uninhabited-mir-call.rs:28:5
+  --> $DIR/privately-uninhabited-mir-call.rs:30:5
    |
 LL |     let y: &mut u32;
    |         - binding declared here but left uninitialized
@@ -9,7 +9,7 @@ LL |     *y = 2;
    |
 help: consider assigning a value
    |
-LL |     let y: &mut u32 = todo!();
+LL |     let y: &mut u32 = &mut 42;
    |                     +++++++++
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr
index c9a440a66cc..782fa63280e 100644
--- a/tests/ui/union/union-borrow-move-parent-sibling.stderr
+++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr
@@ -50,6 +50,11 @@ error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, Moc
 LL |     let a = (u.x.0).0;
    |             ^^^^^^^^^ move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
    |
+note: if `MockVec<u8>` implemented `Clone`, you could clone the value
+  --> $DIR/union-borrow-move-parent-sibling.rs:25:1
+   |
+LL | struct MockVec<T> {
+   | ^^^^^^^^^^^^^^^^^
 help: consider borrowing here
    |
 LL |     let a = &(u.x.0).0;
diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr
index 47fb801a50e..5ebb2716e5a 100644
--- a/tests/ui/union/union-move.stderr
+++ b/tests/ui/union/union-move.stderr
@@ -16,6 +16,11 @@ LL | fn move_out<T>(x: T) {}
    |    --------       ^ this parameter takes ownership of the value
    |    |
    |    in this function
+note: if `U1` implemented `Clone`, you could clone the value
+  --> $DIR/union-move.rs:9:1
+   |
+LL | union U1 {
+   | ^^^^^^^^
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:42:18
@@ -35,6 +40,11 @@ LL | fn move_out<T>(x: T) {}
    |    --------       ^ this parameter takes ownership of the value
    |    |
    |    in this function
+note: if `U1` implemented `Clone`, you could clone the value
+  --> $DIR/union-move.rs:9:1
+   |
+LL | union U1 {
+   | ^^^^^^^^
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:49:18
@@ -44,6 +54,11 @@ LL |         move_out(x.f1_nocopy);
    |                  |
    |                  cannot move out of here
    |                  move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         move_out(x.f1_nocopy.clone());
+   |                             ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/variance/variance-issue-20533.rs b/tests/ui/variance/variance-issue-20533.rs
index a2459f8730c..4c109608906 100644
--- a/tests/ui/variance/variance-issue-20533.rs
+++ b/tests/ui/variance/variance-issue-20533.rs
@@ -19,8 +19,15 @@ fn baz<'a, T>(_x: &'a T) -> Baked<'a> {
     Baked(PhantomData)
 }
 
+fn bat(x: &AffineU32) -> &u32 {
+    &x.0
+}
+
 struct AffineU32(u32);
 
+#[derive(Clone)]
+struct ClonableAffineU32(u32);
+
 fn main() {
     {
         let a = AffineU32(1);
@@ -40,4 +47,16 @@ fn main() {
         drop(a); //~ ERROR cannot move out of `a`
         drop(x);
     }
+    {
+        let a = AffineU32(1);
+        let x = bat(&a);
+        drop(a); //~ ERROR cannot move out of `a`
+        drop(x);
+    }
+    {
+        let a = ClonableAffineU32(1);
+        let x = foo(&a);
+        drop(a); //~ ERROR cannot move out of `a`
+        drop(x);
+    }
 }
diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr
index 258f67db5ce..4515d313ec0 100644
--- a/tests/ui/variance/variance-issue-20533.stderr
+++ b/tests/ui/variance/variance-issue-20533.stderr
@@ -1,5 +1,5 @@
 error[E0505]: cannot move out of `a` because it is borrowed
-  --> $DIR/variance-issue-20533.rs:28:14
+  --> $DIR/variance-issue-20533.rs:35:14
    |
 LL |         let a = AffineU32(1);
    |             - binding `a` declared here
@@ -9,9 +9,15 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+note: if `AffineU32` implemented `Clone`, you could clone the value
+  --> $DIR/variance-issue-20533.rs:26:1
+   |
+LL | struct AffineU32(u32);
+   | ^^^^^^^^^^^^^^^^
 
 error[E0505]: cannot move out of `a` because it is borrowed
-  --> $DIR/variance-issue-20533.rs:34:14
+  --> $DIR/variance-issue-20533.rs:41:14
    |
 LL |         let a = AffineU32(1);
    |             - binding `a` declared here
@@ -21,9 +27,15 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+note: if `AffineU32` implemented `Clone`, you could clone the value
+  --> $DIR/variance-issue-20533.rs:26:1
+   |
+LL | struct AffineU32(u32);
+   | ^^^^^^^^^^^^^^^^
 
 error[E0505]: cannot move out of `a` because it is borrowed
-  --> $DIR/variance-issue-20533.rs:40:14
+  --> $DIR/variance-issue-20533.rs:47:14
    |
 LL |         let a = AffineU32(1);
    |             - binding `a` declared here
@@ -33,7 +45,48 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+note: if `AffineU32` implemented `Clone`, you could clone the value
+  --> $DIR/variance-issue-20533.rs:26:1
+   |
+LL | struct AffineU32(u32);
+   | ^^^^^^^^^^^^^^^^
+
+error[E0505]: cannot move out of `a` because it is borrowed
+  --> $DIR/variance-issue-20533.rs:53:14
+   |
+LL |         let a = AffineU32(1);
+   |             - binding `a` declared here
+LL |         let x = bat(&a);
+   |                     -- borrow of `a` occurs here
+LL |         drop(a);
+   |              ^ move out of `a` occurs here
+LL |         drop(x);
+   |              - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = bat(&a).clone();
+   |                        ++++++++
+
+error[E0505]: cannot move out of `a` because it is borrowed
+  --> $DIR/variance-issue-20533.rs:59:14
+   |
+LL |         let a = ClonableAffineU32(1);
+   |             - binding `a` declared here
+LL |         let x = foo(&a);
+   |                     -- borrow of `a` occurs here
+LL |         drop(a);
+   |              ^ move out of `a` occurs here
+LL |         drop(x);
+   |              - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -         let x = foo(&a);
+LL +         let x = foo(a.clone());
+   |
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0505`.