about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Conjob Bot <miri@cron.bot>2023-09-12 05:31:58 +0000
committerThe Miri Conjob Bot <miri@cron.bot>2023-09-12 05:31:58 +0000
commit5e992f334ca9f6e92d48cb2fdc5d5777f9ba0c0e (patch)
tree600322ffa0911b1e5b459f5ba395672a260d3a41
parent44738528abe0f4da222c514ab49b360e1079cbe1 (diff)
parent366dab13f711df90a6891411458544199d159cbc (diff)
downloadrust-5e992f334ca9f6e92d48cb2fdc5d5777f9ba0c0e.tar.gz
rust-5e992f334ca9f6e92d48cb2fdc5d5777f9ba0c0e.zip
Merge from rustc
-rw-r--r--.gitignore1
-rw-r--r--.mailmap4
-rw-r--r--Cargo.lock3
-rw-r--r--compiler/rustc_abi/src/lib.rs41
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs30
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs5
-rw-r--r--compiler/rustc_borrowck/messages.ftl2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs50
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs126
-rw-r--r--compiler/rustc_borrowck/src/nll.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs33
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs29
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs21
-rw-r--r--compiler/rustc_codegen_cranelift/docs/usage.md2
-rw-r--r--compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml12
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh2
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs248
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs2
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs39
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs79
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs191
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs32
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs164
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs2
-rw-r--r--compiler/rustc_const_eval/src/errors.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs293
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs58
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs58
-rw-r--r--compiler/rustc_data_structures/src/sync.rs6
-rw-r--r--compiler/rustc_data_structures/src/sync/freeze.rs200
-rw-r--r--compiler/rustc_data_structures/src/sync/lock.rs375
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs11
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0401.md6
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs2
-rw-r--r--compiler/rustc_errors/src/emitter.rs4
-rw-r--r--compiler/rustc_errors/src/json.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs8
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl6
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs311
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs64
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs61
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs11
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs26
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs14
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs69
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs15
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs1
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs79
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs20
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs3
-rw-r--r--compiler/rustc_interface/src/interface.rs7
-rw-r--r--compiler/rustc_interface/src/passes.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs8
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl11
-rw-r--r--compiler/rustc_lint/src/context.rs67
-rw-r--r--compiler/rustc_lint/src/errors.rs54
-rw-r--r--compiler/rustc_lint/src/late.rs25
-rw-r--r--compiler/rustc_lint/src/levels.rs95
-rw-r--r--compiler/rustc_lint/src/lints.rs68
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs44
-rw-r--r--compiler/rustc_lint/src/tests.rs2
-rw-r--r--compiler/rustc_lint/src/traits.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs11
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs48
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp95
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp16
-rw-r--r--compiler/rustc_metadata/src/creader.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs47
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs2
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs16
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs55
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs50
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs19
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs221
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs15
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs19
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs5
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs9
-rw-r--r--compiler/rustc_middle/src/ty/context.rs22
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs7
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs37
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs10
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs109
-rw-r--r--compiler/rustc_mir_transform/messages.ftl2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs123
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs323
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs7
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs12
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs5
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs93
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs12
-rw-r--r--compiler/rustc_parse_format/Cargo.toml2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs2
-rw-r--r--compiler/rustc_passes/messages.ftl31
-rw-r--r--compiler/rustc_passes/src/abi_test.rs210
-rw-r--r--compiler/rustc_passes/src/errors.rs39
-rw-r--r--compiler/rustc_passes/src/layout_test.rs94
-rw-r--r--compiler/rustc_passes/src/reachable.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs9
-rw-r--r--compiler/rustc_query_system/src/dep_graph/edges.rs73
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs37
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs8
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs317
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs9
-rw-r--r--compiler/rustc_query_system/src/lib.rs1
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs8
-rw-r--r--compiler/rustc_query_system/src/query/job.rs4
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs6
-rw-r--r--compiler/rustc_resolve/messages.ftl33
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs55
-rw-r--r--compiler/rustc_resolve/src/errors.rs44
-rw-r--r--compiler/rustc_resolve/src/ident.rs10
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--compiler/rustc_resolve/src/macros.rs15
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs89
-rw-r--r--compiler/rustc_serialize/src/opaque.rs2
-rw-r--r--compiler/rustc_session/src/config.rs70
-rw-r--r--compiler/rustc_session/src/cstore.rs6
-rw-r--r--compiler/rustc_session/src/options.rs20
-rw-r--r--compiler/rustc_session/src/session.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs97
-rw-r--r--compiler/rustc_smir/src/stable_mir/fold.rs230
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/body.rs6
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs15
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs75
-rw-r--r--compiler/rustc_smir/src/stable_mir/visitor.rs19
-rw-r--r--compiler/rustc_span/src/lib.rs333
-rw-r--r--compiler/rustc_span/src/source_map.rs14
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs4
-rw-r--r--compiler/rustc_span/src/span_encoding.rs255
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_span/src/tests.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs77
-rw-r--r--compiler/rustc_target/src/abi/call/wasm.rs4
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs23
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs3
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs24
-rw-r--r--compiler/rustc_type_ir/src/lib.rs36
-rw-r--r--config.example.toml8
-rw-r--r--library/core/src/cell.rs1
-rw-r--r--library/core/src/char/methods.rs52
-rw-r--r--library/core/src/error.md2
-rw-r--r--library/core/src/mem/mod.rs5
-rw-r--r--library/core/src/ptr/mut_ptr.rs18
-rw-r--r--library/std/src/io/error.rs4
-rw-r--r--library/std/src/process.rs60
-rw-r--r--library/std/src/sys/unix/process/process_common.rs30
-rw-r--r--library/std/src/sys/unix/thread.rs4
-rw-r--r--library/std/src/sys/unsupported/process.rs20
-rw-r--r--library/std/src/sys/windows/process.rs35
m---------library/stdarch0
-rw-r--r--src/bootstrap/builder.rs7
-rw-r--r--src/bootstrap/builder/tests.rs4
-rw-r--r--src/bootstrap/format.rs4
-rw-r--r--src/bootstrap/lib.rs2
-rw-r--r--src/bootstrap/llvm.rs4
-rw-r--r--src/bootstrap/test.rs126
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh2
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh2
-rw-r--r--src/ci/docker/host-x86_64/wasm32/Dockerfile3
-rwxr-xr-xsrc/ci/run.sh3
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/command-line-arguments.md4
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md33
-rw-r--r--src/doc/rustdoc/src/how-to-read-rustdoc.md16
-rw-r--r--src/doc/rustdoc/src/write-documentation/re-exports.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/path-options.md11
-rw-r--r--src/librustdoc/clean/inline.rs13
-rw-r--r--src/librustdoc/clean/mod.rs138
-rw-r--r--src/librustdoc/clean/types.rs16
-rw-r--r--src/librustdoc/config.rs7
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/doctest.rs5
-rw-r--r--src/librustdoc/fold.rs23
-rw-r--r--src/librustdoc/formats/cache.rs1
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render/context.rs53
-rw-r--r--src/librustdoc/html/render/mod.rs25
-rw-r--r--src/librustdoc/html/render/print_item.rs439
-rw-r--r--src/librustdoc/html/render/sidebar.rs42
-rw-r--r--src/librustdoc/html/static/js/main.js28
-rw-r--r--src/librustdoc/html/static/js/settings.js8
-rw-r--r--src/librustdoc/html/templates/page.html3
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs43
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs7
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs16
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs7
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs34
-rw-r--r--src/librustdoc/passes/lint/unescaped_backticks.rs13
-rw-r--r--src/librustdoc/passes/mod.rs91
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs185
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs84
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs4
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.fixed7
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.rs7
-rw-r--r--src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr14
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed10
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs10
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr13
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs2
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr21
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.rs16
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.rs9
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.stderr42
-rw-r--r--src/tools/miri/src/bin/miri.rs4
-rw-r--r--src/tools/miri/src/diagnostics.rs24
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs (renamed from src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs)0
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr (renamed from src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr)4
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs28
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr15
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs34
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr20
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs (renamed from src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs)0
-rw-r--r--src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr (renamed from src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr)4
-rw-r--r--src/tools/miri/tests/pass/function_calls/abi_compat.rs53
-rw-r--r--tests/codegen/debuginfo-inline-callsite-location.rs28
-rw-r--r--tests/codegen/issues/issue-115385-llvm-jump-threading.rs46
-rw-r--r--tests/codegen/repr/transparent.rs1
-rw-r--r--tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs43
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir18
-rw-r--r--tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff12
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs3
-rw-r--r--tests/mir-opt/const_prop/large_array_index.rs1
-rw-r--r--tests/mir-opt/const_prop/repeat.rs1
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.rs8
-rw-r--r--tests/mir-opt/dataflow-const-prop/boolean_identities.rs10
-rw-r--r--tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff33
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff39
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.rs9
-rw-r--r--tests/mir-opt/dataflow-const-prop/mult_by_zero.rs10
-rw-r--r--tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff72
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff72
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.rs49
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff43
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff43
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff43
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff43
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.rs8
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.rs12
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.rs63
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/funky_arms.rs2
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir6
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir6
-rw-r--r--tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir6
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff8
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff8
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir (renamed from tests/mir-opt/issue_99325.main.built.after.mir)4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir276
-rw-r--r--tests/mir-opt/issue_99325.rs2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir12
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir12
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff3
-rw-r--r--tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff3
-rw-r--r--tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff10
-rw-r--r--tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff5
-rw-r--r--tests/run-make-fulldeps/issue-19371/foo.rs1
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs3
-rw-r--r--tests/run-make/compressed-debuginfo/Makefile15
-rw-r--r--tests/run-make/compressed-debuginfo/foo.rs3
-rw-r--r--tests/run-make/lto-linkage-used-attr/Makefile9
-rw-r--r--tests/run-make/lto-linkage-used-attr/lib.rs50
-rw-r--r--tests/run-make/lto-linkage-used-attr/main.rs10
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/Makefile16
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/main.rs2
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt1
-rw-r--r--tests/run-make/print-cfg/Makefile8
-rw-r--r--tests/rustdoc-gui/help-page.goml18
-rw-r--r--tests/rustdoc-gui/search-no-result.goml12
-rw-r--r--tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs5
-rw-r--r--tests/rustdoc/const-generics/const-generic-defaults.rs2
-rw-r--r--tests/rustdoc/const-generics/const-generics-docs.rs4
-rw-r--r--tests/rustdoc/issue-32077-type-alias-impls.rs66
-rw-r--r--tests/rustdoc/issue-88600.rs4
-rw-r--r--tests/rustdoc/private-fields-tuple-struct.rs15
-rw-r--r--tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs34
-rw-r--r--tests/rustdoc/typedef-inner-variants.rs119
-rw-r--r--tests/rustdoc/where.SWhere_Simd_item-decl.html2
-rw-r--r--tests/rustdoc/where.alpha_trait_decl.html2
-rw-r--r--tests/rustdoc/where.rs2
-rw-r--r--tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr10
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs62
-rw-r--r--tests/ui/abi/compatibility.rs144
-rw-r--r--tests/ui/abi/debug.rs33
-rw-r--r--tests/ui/abi/debug.stderr717
-rw-r--r--tests/ui/associated-consts/associated-const-array-len.stderr6
-rw-r--r--tests/ui/associated-consts/issue-105330.stderr10
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr4
-rw-r--r--tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr6
-rw-r--r--tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr6
-rw-r--r--tests/ui/associated-types/defaults-suitability.stderr5
-rw-r--r--tests/ui/associated-types/issue-23595-2.stderr2
-rw-r--r--tests/ui/associated-types/issue-59324.stderr6
-rw-r--r--tests/ui/associated-types/issue-64855.stderr6
-rw-r--r--tests/ui/associated-types/issue-85103-layout-debug.rs9
-rw-r--r--tests/ui/associated-types/issue-85103-layout-debug.stderr16
-rw-r--r--tests/ui/associated-types/issue-85103.rs9
-rw-r--r--tests/ui/associated-types/issue-85103.stderr8
-rw-r--r--tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr15
-rw-r--r--tests/ui/async-await/async-is-unwindsafe.stderr2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-extra.rs7
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr27
-rw-r--r--tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr11
-rw-r--r--tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs24
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs16
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr33
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed20
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.rs20
-rw-r--r--tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr16
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed36
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs36
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr16
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed30
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.rs30
-rw-r--r--tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr29
-rw-r--r--tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr5
-rw-r--r--tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr6
-rw-r--r--tests/ui/const-generics/early/const-param-from-outer-fn.rs2
-rw-r--r--tests/ui/const-generics/early/const-param-from-outer-fn.stderr8
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-85848.stderr6
-rw-r--r--tests/ui/const-generics/issues/issue-86530.stderr5
-rw-r--r--tests/ui/consts/drop-maybe_uninit.rs17
-rw-r--r--tests/ui/cross/cross-fn-cache-hole.stderr5
-rw-r--r--tests/ui/drop-bounds/drop-bounds-impl-drop.rs10
-rw-r--r--tests/ui/dst/dst-bad-coerce1.stderr10
-rw-r--r--tests/ui/dyn-star/error.stderr6
-rw-r--r--tests/ui/error-codes/E0220.stderr2
-rw-r--r--tests/ui/error-codes/E0277.stderr5
-rw-r--r--tests/ui/error-codes/E0401.stderr22
-rw-r--r--tests/ui/error-codes/E0602.rs2
-rw-r--r--tests/ui/error-codes/E0602.stderr11
-rw-r--r--tests/ui/feature-gates/print-with-path.cfg.stderr2
-rw-r--r--tests/ui/feature-gates/print-with-path.rs7
-rw-r--r--tests/ui/feature-gates/print-with-path.target-cpus.stderr2
-rw-r--r--tests/ui/feature-gates/print-with-path.target-features.stderr2
-rw-r--r--tests/ui/fn/keyword-order.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-101020.stderr5
-rw-r--r--tests/ui/generics/issue-94432-garbage-ice.rs2
-rw-r--r--tests/ui/generics/issue-98432.rs2
-rw-r--r--tests/ui/generics/issue-98432.stderr8
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr15
-rw-r--r--tests/ui/impl-trait/async_scope_creep.rs15
-rw-r--r--tests/ui/impl-trait/async_scope_creep.tait.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr18
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match-works.rs7
-rw-r--r--tests/ui/impl-trait/in-trait/foreign.rs14
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.rs8
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/nested-rpitit.rs10
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/refine.rs48
-rw-r--r--tests/ui/impl-trait/in-trait/refine.stderr67
-rw-r--r--tests/ui/impl-trait/in-trait/reveal.rs5
-rw-r--r--tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.rs12
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-substs-remap.rs5
-rw-r--r--tests/ui/impl-trait/in-trait/success.rs9
-rw-r--r--tests/ui/inner-static-type-parameter.rs2
-rw-r--r--tests/ui/inner-static-type-parameter.stderr6
-rw-r--r--tests/ui/issues/issue-18611.stderr6
-rw-r--r--tests/ui/issues/issue-25076.stderr5
-rw-r--r--tests/ui/issues/issue-3214.rs2
-rw-r--r--tests/ui/issues/issue-3214.stderr8
-rw-r--r--tests/ui/issues/issue-35570.stderr6
-rw-r--r--tests/ui/issues/issue-5997-enum.rs2
-rw-r--r--tests/ui/issues/issue-5997-enum.stderr8
-rw-r--r--tests/ui/issues/issue-5997-struct.rs2
-rw-r--r--tests/ui/issues/issue-5997-struct.stderr8
-rw-r--r--tests/ui/issues/issue-60218.stderr5
-rw-r--r--tests/ui/issues/issue-66353.stderr12
-rw-r--r--tests/ui/layout/debug.rs14
-rw-r--r--tests/ui/layout/debug.stderr46
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.rs44
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.stderr32
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.stderr6
-rw-r--r--tests/ui/lifetimes/issue-95023.stderr2
-rw-r--r--tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr6
-rw-r--r--tests/ui/linkage-attr/common-linkage-non-zero-init.rs14
-rw-r--r--tests/ui/linkage-attr/common-linkage-non-zero-init.stderr3
-rw-r--r--tests/ui/lint/cli-unknown-force-warn.rs6
-rw-r--r--tests/ui/lint/cli-unknown-force-warn.stderr11
-rw-r--r--tests/ui/lint/lint-ctypes-94223.rs7
-rw-r--r--tests/ui/lint/lint-ctypes-94223.stderr27
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs8
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr16
-rw-r--r--tests/ui/lint/lint-removed-cmdline-deny.rs13
-rw-r--r--tests/ui/lint/lint-removed-cmdline-deny.stderr28
-rw-r--r--tests/ui/lint/lint-removed-cmdline.rs1
-rw-r--r--tests/ui/lint/lint-removed-cmdline.stderr5
-rw-r--r--tests/ui/lint/lint-renamed-cmdline-deny.rs10
-rw-r--r--tests/ui/lint/lint-renamed-cmdline-deny.stderr31
-rw-r--r--tests/ui/lint/lint-renamed-cmdline.rs1
-rw-r--r--tests/ui/lint/lint-renamed-cmdline.stderr8
-rw-r--r--tests/ui/lint/lint-unexported-no-mangle.stderr1
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-allow.rs4
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-deny.rs9
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr31
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline.rs2
-rw-r--r--tests/ui/lint/lint-unknown-lint-cmdline.stderr20
-rw-r--r--tests/ui/lint/reference_casting.rs28
-rw-r--r--tests/ui/lint/reference_casting.stderr68
-rw-r--r--tests/ui/namespace/namespace-mix.stderr220
-rw-r--r--tests/ui/nested-ty-params.rs2
-rw-r--r--tests/ui/nested-ty-params.stderr16
-rw-r--r--tests/ui/never_type/feature-gate-never_type_fallback.stderr5
-rw-r--r--tests/ui/never_type/impl_trait_fallback3.stderr6
-rw-r--r--tests/ui/never_type/impl_trait_fallback4.stderr6
-rw-r--r--tests/ui/on-unimplemented/on-trait.stderr10
-rw-r--r--tests/ui/on-unimplemented/parent-label.stderr20
-rw-r--r--tests/ui/parser/default-unmatched.stderr2
-rw-r--r--tests/ui/parser/impl-parsing.stderr2
-rw-r--r--tests/ui/parser/issue-101477-enum.stderr2
-rw-r--r--tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs1
-rw-r--r--tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr10
-rw-r--r--tests/ui/parser/issues/issue-17904-2.stderr2
-rw-r--r--tests/ui/parser/issues/issue-43196.stderr2
-rw-r--r--tests/ui/parser/issues/issue-62913.stderr2
-rw-r--r--tests/ui/parser/issues/issue-68890.stderr2
-rw-r--r--tests/ui/parser/shebang/shebang-doc-comment.stderr2
-rw-r--r--tests/ui/parser/virtual-structs.stderr2
-rw-r--r--tests/ui/pattern/issue-114896.rs7
-rw-r--r--tests/ui/pattern/issue-114896.stderr11
-rw-r--r--tests/ui/privacy/private-bounds-locally-allowed.rs7
-rw-r--r--tests/ui/privacy/unnameable_types.rs8
-rw-r--r--tests/ui/proc-macro/bad-projection.stderr6
-rw-r--r--tests/ui/pub/pub-restricted-error-fn.stderr2
-rw-r--r--tests/ui/resolve/bad-type-env-capture.stderr8
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr28
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr34
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs39
-rw-r--r--tests/ui/resolve/issue-12796.rs2
-rw-r--r--tests/ui/resolve/issue-12796.stderr4
-rw-r--r--tests/ui/resolve/issue-3021-c.rs4
-rw-r--r--tests/ui/resolve/issue-3021-c.stderr16
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.rs2
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr6
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.rs10
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.stderr30
-rw-r--r--tests/ui/resolve/resolve-type-param-in-item-in-trait.rs8
-rw-r--r--tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr32
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed16
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.rs15
-rw-r--r--tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr14
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.rs6
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs9
-rw-r--r--tests/ui/sanitize/cfg.rs16
-rw-r--r--tests/ui/span/issue-29595.stderr6
-rw-r--r--tests/ui/specialization/issue-38091.stderr5
-rw-r--r--tests/ui/suggestions/issue-89333.stderr5
-rw-r--r--tests/ui/thir-print/thir-flat-const-variant.stdout96
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout20
-rw-r--r--tests/ui/trait-bounds/issue-82038.rs9
-rw-r--r--tests/ui/trait-bounds/issue-82038.stderr15
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr10
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr5
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-locals.stderr10
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-static.stderr5
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums.stderr20
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.current.stderr5
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.next.stderr5
-rw-r--r--tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr5
-rw-r--r--tests/ui/traits/impl-bounds-checking.stderr5
-rw-r--r--tests/ui/traits/new-solver/projection-discr-kind.stderr5
-rw-r--r--tests/ui/traits/non_lifetime_binders/fail.stderr5
-rw-r--r--tests/ui/traits/object-does-not-impl-trait.stderr5
-rw-r--r--tests/ui/traits/object/enforce-supertrait-projection.rs2
-rw-r--r--tests/ui/traits/object/enforce-supertrait-projection.stderr2
-rw-r--r--tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs15
-rw-r--r--tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr22
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-39029.fixed (renamed from tests/ui/traits/suggest-deferences/issue-39029.fixed)0
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-39029.rs (renamed from tests/ui/traits/suggest-deferences/issue-39029.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-39029.stderr (renamed from tests/ui/traits/suggest-deferences/issue-39029.stderr)0
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-62530.fixed (renamed from tests/ui/traits/suggest-deferences/issue-62530.fixed)0
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-62530.rs (renamed from tests/ui/traits/suggest-deferences/issue-62530.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-62530.stderr (renamed from tests/ui/traits/suggest-deferences/issue-62530.stderr)0
-rw-r--r--tests/ui/traits/suggest-dereferences/multiple-0.fixed (renamed from tests/ui/traits/suggest-deferences/multiple-0.fixed)0
-rw-r--r--tests/ui/traits/suggest-dereferences/multiple-0.rs (renamed from tests/ui/traits/suggest-deferences/multiple-0.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/multiple-0.stderr (renamed from tests/ui/traits/suggest-deferences/multiple-0.stderr)0
-rw-r--r--tests/ui/traits/suggest-dereferences/multiple-1.rs (renamed from tests/ui/traits/suggest-deferences/multiple-1.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/multiple-1.stderr (renamed from tests/ui/traits/suggest-deferences/multiple-1.stderr)0
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.fixed (renamed from tests/ui/traits/suggest-deferences/root-obligation.fixed)0
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.rs (renamed from tests/ui/traits/suggest-deferences/root-obligation.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.stderr (renamed from tests/ui/traits/suggest-deferences/root-obligation.stderr)0
-rw-r--r--tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed (renamed from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed)0
-rw-r--r--tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs (renamed from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs)0
-rw-r--r--tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr (renamed from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr)0
-rw-r--r--tests/ui/traits/vtable-res-trait-param.stderr5
-rw-r--r--tests/ui/trivial-bounds/trivial-bounds-leak.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs25
-rw-r--r--tests/ui/type/type-arg-out-of-scope.rs2
-rw-r--r--tests/ui/type/type-arg-out-of-scope.stderr16
-rw-r--r--tests/ui/union/projection-as-union-type-error-2.stderr5
-rw-r--r--tests/ui/union/projection-as-union-type-error.stderr6
-rw-r--r--tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs16
-rw-r--r--tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr21
-rw-r--r--tests/ui/unsized/issue-115203.rs11
-rw-r--r--tests/ui/unsized/issue-115203.stderr19
-rw-r--r--tests/ui/unsized/issue-75707.stderr5
-rw-r--r--tests/ui/wf/hir-wf-canonicalized.stderr12
-rw-r--r--tests/ui/wf/issue-95665.stderr5
-rw-r--r--tests/ui/wf/wf-complex-assoc-type.stderr5
-rw-r--r--tests/ui/wf/wf-foreign-fn-decl-ret.stderr11
-rw-r--r--tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr6
-rw-r--r--tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr5
-rw-r--r--tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr5
-rw-r--r--tests/ui/where-clauses/where-clause-method-substituion.stderr5
613 files changed, 12288 insertions, 3425 deletions
diff --git a/.gitignore b/.gitignore
index 485968d9c56..4c8d1a03764 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@ build/
 \#*
 \#*\#
 .#*
+rustc-ice-*.txt
 
 ## Tags
 tags
diff --git a/.mailmap b/.mailmap
index c072f6282f1..eb82cf4de8d 100644
--- a/.mailmap
+++ b/.mailmap
@@ -205,6 +205,10 @@ Gareth Daniel Smith <garethdanielsmith@gmail.com> gareth <gareth@gareth-N56VM.(n
 Gareth Daniel Smith <garethdanielsmith@gmail.com> Gareth Smith <garethdanielsmith@gmail.com>
 Gauri Kholkar <f2013002@goa.bits-pilani.ac.in>
 Georges Dubus <georges.dubus@gmail.com> <georges.dubus@compiletoi.net>
+Ghost <ghost> <jonasschievink@gmail.com>
+Ghost <ghost> <jonas.schievink@ferrous-systems.com>
+Ghost <ghost> <jonas@schievink.net>
+Ghost <ghost> <Jonas.Schievink@sony.com>
 Giles Cope <gilescope@gmail.com>
 Glen De Cauwsemaecker <decauwsemaecker.glen@gmail.com>
 Graham Fawcett <graham.fawcett@gmail.com> Graham Fawcett <fawcett@uwindsor.ca>
diff --git a/Cargo.lock b/Cargo.lock
index 35a9fdccf9c..295a5b43a6f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -558,7 +558,6 @@ dependencies = [
  "declare_clippy_lint",
  "if_chain",
  "itertools",
- "pulldown-cmark",
  "quine-mc_cluskey",
  "regex",
  "regex-syntax 0.7.2",
@@ -4175,7 +4174,7 @@ dependencies = [
 name = "rustc_parse_format"
 version = "0.0.0"
 dependencies = [
- "rustc_data_structures",
+ "rustc_index",
  "rustc_lexer",
 ]
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 571aaf631bd..b30ff058a30 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1300,12 +1300,18 @@ impl Abi {
         matches!(*self, Abi::Uninhabited)
     }
 
-    /// Returns `true` is this is a scalar type
+    /// Returns `true` if this is a scalar type
     #[inline]
     pub fn is_scalar(&self) -> bool {
         matches!(*self, Abi::Scalar(_))
     }
 
+    /// Returns `true` if this is a bool
+    #[inline]
+    pub fn is_bool(&self) -> bool {
+        matches!(*self, Abi::Scalar(s) if s.is_bool())
+    }
+
     /// Returns the fixed alignment of this ABI, if any is mandated.
     pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
         Some(match *self {
@@ -1348,6 +1354,23 @@ impl Abi {
             Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
         }
     }
+
+    pub fn eq_up_to_validity(&self, other: &Self) -> bool {
+        match (self, other) {
+            // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges.
+            // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x).
+            (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(),
+            (
+                Abi::Vector { element: element_l, count: count_l },
+                Abi::Vector { element: element_r, count: count_r },
+            ) => element_l.primitive() == element_r.primitive() && count_l == count_r,
+            (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => {
+                l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
+            }
+            // Everything else must be strictly identical.
+            _ => self == other,
+        }
+    }
 }
 
 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
@@ -1686,6 +1709,22 @@ impl LayoutS {
             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
         }
     }
+
+    /// Checks if these two `Layout` are equal enough to be considered "the same for all function
+    /// call ABIs". Note however that real ABIs depend on more details that are not reflected in the
+    /// `Layout`; the `PassMode` need to be compared as well.
+    pub fn eq_abi(&self, other: &Self) -> bool {
+        // The one thing that we are not capturing here is that for unsized types, the metadata must
+        // also have the same ABI, and moreover that the same metadata leads to the same size. The
+        // 2nd point is quite hard to check though.
+        self.size == other.size
+            && self.is_sized() == other.is_sized()
+            && self.abi.eq_up_to_validity(&other.abi)
+            && self.abi.is_bool() == other.abi.is_bool()
+            && self.align.abi == other.align.abi
+            && self.max_repr_align == other.max_repr_align
+            && self.unadjusted_abi_align == other.unadjusted_abi_align
+    }
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index ce847906fb9..eff362f3ff0 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -2,19 +2,17 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::definitions;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::*;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::span_bug;
-use rustc_session::Session;
-use rustc_span::source_map::SourceMap;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::{Span, DUMMY_SP};
 
 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
 pub(super) struct NodeCollector<'a, 'hir> {
-    /// Source map
-    source_map: &'a SourceMap,
+    tcx: TyCtxt<'hir>,
+
     bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
 
     /// Outputs
@@ -25,14 +23,11 @@ pub(super) struct NodeCollector<'a, 'hir> {
     parent_node: hir::ItemLocalId,
 
     owner: OwnerId,
-
-    definitions: &'a definitions::Definitions,
 }
 
-#[instrument(level = "debug", skip(sess, definitions, bodies))]
+#[instrument(level = "debug", skip(tcx, bodies))]
 pub(super) fn index_hir<'hir>(
-    sess: &Session,
-    definitions: &definitions::Definitions,
+    tcx: TyCtxt<'hir>,
     item: hir::OwnerNode<'hir>,
     bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
 ) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
@@ -42,8 +37,7 @@ pub(super) fn index_hir<'hir>(
     // used.
     nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
     let mut collector = NodeCollector {
-        source_map: sess.source_map(),
-        definitions,
+        tcx,
         owner: item.def_id(),
         parent_node: ItemLocalId::new(0),
         nodes,
@@ -79,11 +73,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                     span,
                     "inconsistent HirId at `{:?}` for `{:?}`: \
                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
-                    self.source_map.span_to_diagnostic_string(span),
+                    self.tcx.sess.source_map().span_to_diagnostic_string(span),
                     node,
-                    self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(),
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(self.owner.def_id)
+                        .to_string_no_crate_verbose(),
                     self.owner,
-                    self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(hir_id.owner.def_id)
+                        .to_string_no_crate_verbose(),
                     hir_id.owner,
                 )
             }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a6d1ef33f40..32046b0febf 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -671,8 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         } else {
             (None, None)
         };
-        let (nodes, parenting) =
-            index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
+        let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies);
         let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
         let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
 
@@ -771,7 +770,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.tcx.sess.opts.incremental_relative_spans() {
+        if self.tcx.sess.opts.incremental.is_some() {
             span.with_parent(Some(self.current_hir_id_owner.def_id))
         } else {
             // Do not make spans relative when not using incremental compilation.
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index 67fdb671742..d8ca62565fa 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -166,6 +166,8 @@ borrowck_returned_lifetime_wrong =
 borrowck_returned_ref_escaped =
     returns a reference to a captured variable which escapes the closure body
 
+borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
+
 borrowck_suggest_create_freash_reborrow =
     consider reborrowing the `Pin` instead of moving it
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index fe4a45b3898..48d09f2c2b2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
                 /// We could expand the analysis to suggest hoising all of the relevant parts of
                 /// the users' code to make the code compile, but that could be too much.
-                struct NestedStatementVisitor {
+                /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
+                /// which is a special case since it's generated by the compiler.
+                struct NestedStatementVisitor<'tcx> {
                     span: Span,
                     current: usize,
                     found: usize,
+                    prop_expr: Option<&'tcx hir::Expr<'tcx>>,
                 }
 
-                impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
-                    fn visit_block(&mut self, block: &hir::Block<'tcx>) {
+                impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
+                    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
                         self.current += 1;
                         walk_block(self, block);
                         self.current -= 1;
                     }
-                    fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
+                    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                         if self.span == expr.span.source_callsite() {
                             self.found = self.current;
+                            if self.prop_expr.is_none() {
+                                self.prop_expr = Some(expr);
+                            }
                         }
                         walk_expr(self, expr);
                     }
@@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             span: proper_span,
                             current: 0,
                             found: 0,
+                            prop_expr: None,
                         };
                         visitor.visit_stmt(stmt);
+
+                        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+                        let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
+
+                        let is_format_arguments_item =
+                            if let Some(expr_ty) = expr_ty
+                               && let ty::Adt(adt, _) = expr_ty.kind() {
+                                    self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
+                               } else {
+                                   false
+                               };
+
                         if visitor.found == 0
                             && stmt.span.contains(proper_span)
                             && let Some(p) = sm.span_to_margin(stmt.span)
                             && let Ok(s) = sm.span_to_snippet(proper_span)
                         {
-                            let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
-                            err.multipart_suggestion_verbose(
-                                msg,
-                                vec![
-                                    (stmt.span.shrink_to_lo(), addition),
-                                    (proper_span, "binding".to_string()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
+                            if !is_format_arguments_item {
+                                let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
+                                err.multipart_suggestion_verbose(
+                                    msg,
+                                    vec![
+                                        (stmt.span.shrink_to_lo(), addition),
+                                        (proper_span, "binding".to_string()),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used");
+                                err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
+                            }
                             suggested = true;
                             break;
                         }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 31e863b8a4e..a0edeec59d0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,9 +1,10 @@
+use hir::ExprKind;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
 use rustc_middle::{
     hir::place::PlaceBase,
     mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -370,12 +371,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     err.span_label(span, format!("cannot {act}"));
                 }
                 if suggest {
-                    err.span_suggestion_verbose(
-                        local_decl.source_info.span.shrink_to_lo(),
-                        "consider changing this to be mutable",
-                        "mut ",
-                        Applicability::MachineApplicable,
-                    );
+                    self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
                     let tcx = self.infcx.tcx;
                     if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
                         self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
@@ -491,6 +487,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             ),
                         );
 
+                        self.suggest_using_iter_mut(&mut err);
                         self.suggest_make_local_mut(&mut err, local, name);
                     }
                     _ => {
@@ -710,6 +707,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         )
     }
 
+    fn construct_mut_suggestion_for_local_binding_patterns(
+        &self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        local: Local,
+    ) {
+        let local_decl = &self.body.local_decls[local];
+        debug!("local_decl: {:?}", local_decl);
+        let pat_span = match *local_decl.local_info() {
+            LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+                opt_ty_info: _,
+                opt_match_place: _,
+                pat_span,
+            })) => pat_span,
+            _ => local_decl.source_info.span,
+        };
+
+        struct BindingFinder {
+            span: Span,
+            hir_id: Option<hir::HirId>,
+        }
+
+        impl<'tcx> Visitor<'tcx> for BindingFinder {
+            fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+                if let hir::StmtKind::Local(local) = s.kind {
+                    if local.pat.span == self.span {
+                        self.hir_id = Some(local.hir_id);
+                    }
+                }
+                hir::intravisit::walk_stmt(self, s);
+            }
+        }
+
+        let hir_map = self.infcx.tcx.hir();
+        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) = hir_map.maybe_body_owned_by(local_def_id)
+        {
+            let body = hir_map.body(body_id);
+            let mut v = BindingFinder {
+                span: pat_span,
+                hir_id: None,
+            };
+            v.visit_body(body);
+            v.hir_id
+        } else {
+            None
+        };
+
+        // With ref-binding patterns, the mutability suggestion has to apply to
+        // the binding, not the reference (which would be a type error):
+        //
+        // `let &b = a;` -> `let &(mut b) = a;`
+        if let Some(hir_id) = hir_id
+            && let Some(hir::Node::Local(hir::Local {
+                pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
+                ..
+            })) = hir_map.find(hir_id)
+            && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
+        {
+            err.span_suggestion(
+                pat_span,
+                "consider changing this to be mutable",
+                format!("&(mut {name})"),
+                Applicability::MachineApplicable,
+            );
+            return;
+        }
+
+        err.span_suggestion_verbose(
+            local_decl.source_info.span.shrink_to_lo(),
+            "consider changing this to be mutable",
+            "mut ",
+            Applicability::MachineApplicable,
+        );
+    }
+
     // point to span of upvar making closure call require mutable borrow
     fn show_mutating_upvar(
         &self,
@@ -953,6 +1027,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) {
+        let source = self.body.source;
+        let hir = self.infcx.tcx.hir();
+        if let InstanceDef::Item(def_id) = source.instance
+            && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
+            && let ExprKind::Closure(closure) = kind && closure.movability == None
+            && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
+                let mut cur_expr = expr;
+                while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
+                    if path_segment.ident.name == sym::iter {
+                        // check `_ty` has `iter_mut` method
+                        let res = self
+                            .infcx
+                            .tcx
+                            .typeck(path_segment.hir_id.owner.def_id)
+                            .type_dependent_def_id(cur_expr.hir_id)
+                            .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+                            .map(|def_id| self.infcx.tcx.associated_items(def_id))
+                            .map(|assoc_items| {
+                                assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
+                            });
+
+                        if let Some(mut res) = res && res.peek().is_some() {
+                            err.span_suggestion_verbose(
+                                path_segment.ident.span,
+                                "you may want to use `iter_mut` here",
+                                "iter_mut",
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                        break;
+                    } else {
+                        cur_expr = recv;
+                    }
+                }
+            }
+    }
+
     fn suggest_make_local_mut(
         &self,
         err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 679a19710a7..3f60f5aca71 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::{
     Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
     START_BLOCK,
 };
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_span::symbol::sym;
 use std::env;
@@ -441,7 +442,10 @@ fn for_each_region_constraint<'tcx>(
         let subject = match req.subject {
             ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"),
             ClosureOutlivesSubject::Ty(ty) => {
-                format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)))
+                with_no_trimmed_paths!(format!(
+                    "{}",
+                    ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))
+                ))
             }
         };
         with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?;
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4da7b602571..b7da15af6dc 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -328,19 +328,26 @@ fn check_opaque_type_well_formed<'tcx>(
 
     // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
     // the bounds that the function supplies.
-    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
-    ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
-        .map_err(|err| {
-            infcx
-                .err_ctxt()
-                .report_mismatched_types(
-                    &ObligationCause::misc(definition_span, def_id),
-                    opaque_ty,
-                    definition_ty,
-                    err,
-                )
-                .emit()
-        })?;
+    let mut obligations = vec![];
+    infcx
+        .insert_hidden_type(
+            OpaqueTypeKey { def_id, args: identity_args },
+            &ObligationCause::misc(definition_span, def_id),
+            param_env,
+            definition_ty,
+            true,
+            &mut obligations,
+        )
+        .unwrap();
+    infcx.add_item_bounds_for_hidden_type(
+        def_id.to_def_id(),
+        identity_args,
+        ObligationCause::misc(definition_span, def_id),
+        param_env,
+        definition_ty,
+        &mut obligations,
+    );
+    ocx.register_obligations(obligations);
 
     // Require the hidden type to be well-formed with only the generics of the opaque type.
     // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index d1d8cfa74aa..ca3ccf439f2 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -452,3 +452,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
     #[note(borrowck_ty_no_impl_copy)]
     Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
 }
+
+#[derive(Diagnostic)]
+#[diag(borrowck_simd_shuffle_last_const)]
+pub(crate) struct SimdShuffleLastConst {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 28286243e82..0f661421cdc 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -50,7 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
-use crate::session_diagnostics::MoveUnsized;
+use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
 use crate::{
     borrow_set::BorrowSet,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -1426,7 +1426,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         .add_element(region_vid, term_location);
                 }
 
-                self.check_call_inputs(body, term, &sig, args, term_location, *call_source);
+                self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source);
             }
             TerminatorKind::Assert { cond, msg, .. } => {
                 self.check_operand(cond, term_location);
@@ -1546,25 +1546,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))]
     fn check_call_inputs(
         &mut self,
         body: &Body<'tcx>,
         term: &Terminator<'tcx>,
+        func: &Operand<'tcx>,
         sig: &ty::FnSig<'tcx>,
         args: &[Operand<'tcx>],
         term_location: Location,
         call_source: CallSource,
     ) {
-        debug!("check_call_inputs({:?}, {:?})", sig, args);
         if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
 
-        let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
-            Some(func.ty(body, self.infcx.tcx))
-        } else {
-            None
-        };
+        let func_ty = func.ty(body, self.infcx.tcx);
+        if let ty::FnDef(def_id, _) = *func_ty.kind() {
+            if self.tcx().is_intrinsic(def_id) {
+                match self.tcx().item_name(def_id) {
+                    sym::simd_shuffle => {
+                        if !matches!(args[2], Operand::Constant(_)) {
+                            self.tcx()
+                                .sess
+                                .emit_err(SimdShuffleLastConst { span: term.source_info.span });
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
         debug!(?func_ty);
 
         for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
@@ -1572,7 +1583,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if call_source.from_hir_call() {
-                ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
+                ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty)))
             } else {
                 ConstraintCategory::Boring
             };
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 56945f43fcd..3b5f1178db5 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -21,6 +21,7 @@ use rustc_hir::BodyOwnerKind;
 use rustc_index::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_span::symbol::{kw, sym};
@@ -332,10 +333,16 @@ impl<'tcx> UniversalRegions<'tcx> {
     pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
         match self.defining_ty {
             DefiningTy::Closure(def_id, args) => {
+                let v = with_no_trimmed_paths!(
+                    args[tcx.generics_of(def_id).parent_count..]
+                        .iter()
+                        .map(|arg| arg.to_string())
+                        .collect::<Vec<_>>()
+                );
                 err.note(format!(
-                    "defining type: {} with closure args {:#?}",
+                    "defining type: {} with closure args [\n    {},\n]",
                     tcx.def_path_str_with_args(def_id, args),
-                    &args[tcx.generics_of(def_id).parent_count..],
+                    v.join(",\n    "),
                 ));
 
                 // FIXME: It'd be nice to print the late-bound regions
@@ -348,10 +355,16 @@ impl<'tcx> UniversalRegions<'tcx> {
                 });
             }
             DefiningTy::Generator(def_id, args, _) => {
+                let v = with_no_trimmed_paths!(
+                    args[tcx.generics_of(def_id).parent_count..]
+                        .iter()
+                        .map(|arg| arg.to_string())
+                        .collect::<Vec<_>>()
+                );
                 err.note(format!(
-                    "defining type: {} with generator args {:#?}",
+                    "defining type: {} with generator args [\n    {},\n]",
                     tcx.def_path_str_with_args(def_id, args),
-                    &args[tcx.generics_of(def_id).parent_count..],
+                    v.join(",\n    "),
                 ));
 
                 // FIXME: As above, we'd like to print out the region
diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md
index c6210f958d6..135a51ce392 100644
--- a/compiler/rustc_codegen_cranelift/docs/usage.md
+++ b/compiler/rustc_codegen_cranelift/docs/usage.md
@@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell
 
 ```bash
 function jit_naked() {
-    echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+    echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic
 }
 
 function jit() {
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
index fa175edcae6..5b79d6569bb 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.20.0"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -140,9 +140,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.27.2"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -205,9 +205,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.31.1"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
+checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
 dependencies = [
  "compiler_builtins",
  "memchr",
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 5689bdee64d..2cc5d7777a6 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-08-08"
+channel = "nightly-2023-09-06"
 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 c163b854384..3fc462a39cc 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -45,6 +45,7 @@ rm tests/ui/proc-macro/quote-debug.rs
 rm tests/ui/proc-macro/no-missing-docs.rs
 rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs
 rm tests/ui/proc-macro/allowed-signatures.rs
+rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
 
 # vendor intrinsics
 rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
@@ -114,6 +115,7 @@ rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/layout/valid_range_oob.rs # different ICE message
+rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif
 
 rm tests/ui/consts/issue-miri-1910.rs # different error message
 rm tests/ui/consts/offset_ub.rs # same
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
index 998263de584..b19b935a0fe 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
@@ -81,7 +81,7 @@ impl DebugContext {
 
         match tcx.sess.source_map().lookup_line(span.lo()) {
             Ok(SourceFileAndLine { sf: file, line }) => {
-                let line_pos = file.lines(|lines| lines[line]);
+                let line_pos = file.lines()[line];
                 let col = file.relative_position(span.lo()) - line_pos;
 
                 (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1)
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index fdd27a454e0..e62de6b6147 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -177,244 +177,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
                 bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
             });
         }
-        "llvm.x86.sse2.psrli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.psrai.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrai.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.pslli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.pslli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.psrli.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.psrai.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.psrai.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.pslli.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.sse2.pslli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx.psrli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.psrli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx.psrai.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.psrai.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.psrli.q" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.psrli.q imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 64 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.sse2.pslli.q" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.pslli.q imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 64 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx.pslli.d" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.pslli.d imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx2.psrli.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.psrli.w imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx2.psrai.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.psrai.w imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
-        "llvm.x86.avx2.pslli.w" => {
-            let (a, imm8) = match args {
-                [a, imm8] => (a, imm8),
-                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
-            };
-            let a = codegen_operand(fx, a);
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
-                .expect("llvm.x86.avx.pslli.w imm8 not const");
-
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
-                .try_to_bits(Size::from_bytes(4))
-                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
-            {
-                imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                _ => fx.bcx.ins().iconst(types::I32, 0),
-            });
-        }
         "llvm.x86.ssse3.pshuf.b.128" | "llvm.x86.avx2.pshuf.b" => {
             let (a, b) = match args {
                 [a, b] => (a, b),
@@ -506,14 +268,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             ret.place_lane(fx, 2).to_ptr().store(fx, res_2, MemFlags::trusted());
             ret.place_lane(fx, 3).to_ptr().store(fx, res_3, MemFlags::trusted());
         }
-        "llvm.x86.sse2.storeu.dq" | "llvm.x86.sse2.storeu.pd" => {
-            intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
-            let mem_addr = mem_addr.load_scalar(fx);
-
-            // FIXME correctly handle the unalignment
-            let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
-            dest.write_cvalue(fx, a);
-        }
         "llvm.x86.ssse3.pabs.b.128" | "llvm.x86.ssse3.pabs.w.128" | "llvm.x86.ssse3.pabs.d.128" => {
             let a = match args {
                 [a] => a,
@@ -571,8 +325,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 // llvm.x86.avx2.vperm2i128
 // llvm.x86.ssse3.pshuf.b.128
 // llvm.x86.avx2.pshuf.b
-// llvm.x86.avx2.psrli.w
-// llvm.x86.sse2.psrli.w
 
 fn llvm_add_sub<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index a81585d4128..d1bfd833cd8 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         _fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         _llfn: RValue<'gcc>,
         _mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
+    ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
         // TODO(antoyo)
         None
     }
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index aed4a8f3c85..ddaff36f24b 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix =
     unknown feature specified for `-Ctarget-feature`: `{$feature}`
     .note = features must begin with a `+` to enable or `-` to disable it
 
+codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
+
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
 
 codegen_llvm_write_ir = failed to write LLVM IR to {$path}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 863cb7068f8..64587f98b8a 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -340,15 +340,50 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         };
 
         for arg in args {
+            // Note that the exact number of arguments pushed here is carefully synchronized with
+            // code all over the place, both in the codegen_llvm and codegen_ssa crates. That's how
+            // other code then knows which LLVM argument(s) correspond to the n-th Rust argument.
             let llarg_ty = match &arg.mode {
                 PassMode::Ignore => continue,
-                PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
+                PassMode::Direct(_) => {
+                    // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
+                    // and for Scalar ABIs the LLVM type is fully determined by `layout.abi`,
+                    // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
+                    // aggregates...
+                    if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
+                        // This really shouldn't happen, since `immediate_llvm_type` will use
+                        // `layout.fields` to turn this Rust type into an LLVM type. This means all
+                        // sorts of Rust type details leak into the ABI. However wasm sadly *does*
+                        // currently use this mode so we have to allow it -- but we absolutely
+                        // shouldn't let any more targets do that.
+                        // (Also see <https://github.com/rust-lang/rust/issues/115666>.)
+                        assert!(
+                            matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"),
+                            "`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}",
+                            arg.layout,
+                        );
+                    }
+                    arg.layout.immediate_llvm_type(cx)
+                }
                 PassMode::Pair(..) => {
+                    // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
+                    // so for ScalarPair we can easily be sure that we are generating ABI-compatible
+                    // LLVM IR.
+                    assert!(
+                        matches!(arg.layout.abi, abi::Abi::ScalarPair(..)),
+                        "PassMode::Pair for type {}",
+                        arg.layout.ty
+                    );
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
                     continue;
                 }
                 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+                    assert!(arg.layout.is_unsized());
+                    // Construct the type of a (wide) pointer to `ty`, and pass its two fields.
+                    // Any two ABI-compatible unsized types have the same metadata type and
+                    // moreover the same metadata value leads to the same dynamic size and
+                    // alignment, so this respects ABI compatibility.
                     let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty);
                     let ptr_layout = cx.layout_of(ptr_ty);
                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
@@ -360,6 +395,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     if *pad_i32 {
                         llargument_tys.push(Reg::i32().llvm_type(cx));
                     }
+                    // Compute the LLVM type we use for this function from the cast type.
+                    // We assume here that ABI-compatible Rust types have the same cast type.
                     cast.llvm_type(cx)
                 }
                 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index c1d3392386c..5cf83b1accb 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,4 +1,6 @@
-use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers};
+use crate::back::write::{
+    self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers,
+};
 use crate::errors::{
     DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
 };
@@ -120,6 +122,7 @@ fn prepare_lto(
                 info!("adding bitcode from {}", name);
                 match get_bitcode_slice_from_object_data(
                     child.data(&*archive_data).expect("corrupt rlib"),
+                    cgcx,
                 ) {
                     Ok(data) => {
                         let module = SerializedModule::FromRlib(data.to_vec());
@@ -141,10 +144,29 @@ fn prepare_lto(
     Ok((symbols_below_threshold, upstream_modules))
 }
 
-fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> {
+fn get_bitcode_slice_from_object_data<'a>(
+    obj: &'a [u8],
+    cgcx: &CodegenContext<LlvmCodegenBackend>,
+) -> Result<&'a [u8], LtoBitcodeFromRlib> {
+    // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that
+    // won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff
+    // the relevant magic strings here and return.
+    if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") {
+        return Ok(obj);
+    }
+    // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name"
+    // which in the public API for sections gets treated as part of the section name, but internally
+    // in MachOObjectFile.cpp gets treated separately.
+    let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,");
     let mut len = 0;
-    let data =
-        unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) };
+    let data = unsafe {
+        llvm::LLVMRustGetSliceFromObjectDataByName(
+            obj.as_ptr(),
+            obj.len(),
+            section_name.as_ptr(),
+            &mut len,
+        )
+    };
     if !data.is_null() {
         assert!(len != 0);
         let bc = unsafe { slice::from_raw_parts(data, len) };
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 47cc5bd52e2..1f394a7335c 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -5,13 +5,17 @@ use crate::back::profiling::{
 use crate::base;
 use crate::common;
 use crate::errors::{
-    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
+    CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
+    WithLlvmError, WriteBytecode,
 };
 use crate::llvm::{self, DiagnosticInfo, PassManager};
 use crate::llvm_util;
 use crate::type_::Type;
 use crate::LlvmCodegenBackend;
 use crate::ModuleLlvm;
+use llvm::{
+    LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
+};
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{
     BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
@@ -216,6 +220,40 @@ pub fn target_machine_factory(
 
     let force_emulated_tls = sess.target.force_emulated_tls;
 
+    // copy the exe path, followed by path all into one buffer
+    // null terminating them so we can use them as null terminated strings
+    let args_cstr_buff = {
+        let mut args_cstr_buff: Vec<u8> = Vec::new();
+        let exe_path = std::env::current_exe().unwrap_or_default();
+        let exe_path_str = exe_path.into_os_string().into_string().unwrap_or_default();
+
+        args_cstr_buff.extend_from_slice(exe_path_str.as_bytes());
+        args_cstr_buff.push(0);
+
+        for arg in sess.expanded_args.iter() {
+            args_cstr_buff.extend_from_slice(arg.as_bytes());
+            args_cstr_buff.push(0);
+        }
+
+        args_cstr_buff
+    };
+
+    let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
+    match sess.opts.debuginfo_compression {
+        rustc_session::config::DebugInfoCompression::Zlib => {
+            if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
+                sess.emit_warning(UnknownCompression { algorithm: "zlib" });
+            }
+        }
+        rustc_session::config::DebugInfoCompression::Zstd => {
+            if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
+                sess.emit_warning(UnknownCompression { algorithm: "zstd" });
+            }
+        }
+        rustc_session::config::DebugInfoCompression::None => {}
+    };
+    let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
+
     Arc::new(move |config: TargetMachineFactoryConfig| {
         let split_dwarf_file =
             path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
@@ -241,7 +279,10 @@ pub fn target_machine_factory(
                 relax_elf_relocations,
                 use_init_array,
                 split_dwarf_file.as_ptr(),
+                debuginfo_compression.as_ptr(),
                 force_emulated_tls,
+                args_cstr_buff.as_ptr() as *const c_char,
+                args_cstr_buff.len(),
             )
         };
 
@@ -853,6 +894,27 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data:
     asm
 }
 
+fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
+    cgcx.opts.target_triple.triple().contains("-ios")
+        || cgcx.opts.target_triple.triple().contains("-darwin")
+        || cgcx.opts.target_triple.triple().contains("-tvos")
+        || cgcx.opts.target_triple.triple().contains("-watchos")
+}
+
+fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
+    cgcx.opts.target_triple.triple().contains("-aix")
+}
+
+pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str {
+    if target_is_apple(cgcx) {
+        "__LLVM,__bitcode\0"
+    } else if target_is_aix(cgcx) {
+        ".ipa\0"
+    } else {
+        ".llvmbc\0"
+    }
+}
+
 /// Embed the bitcode of an LLVM module in the LLVM module itself.
 ///
 /// This is done primarily for iOS where it appears to be standard to compile C
@@ -913,11 +975,8 @@ unsafe fn embed_bitcode(
     // Unfortunately, LLVM provides no way to set custom section flags. For ELF
     // and COFF we emit the sections using module level inline assembly for that
     // reason (see issue #90326 for historical background).
-    let is_aix = cgcx.opts.target_triple.triple().contains("-aix");
-    let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
-        || cgcx.opts.target_triple.triple().contains("-darwin")
-        || cgcx.opts.target_triple.triple().contains("-tvos")
-        || cgcx.opts.target_triple.triple().contains("-watchos");
+    let is_aix = target_is_aix(cgcx);
+    let is_apple = target_is_apple(cgcx);
     if is_apple
         || is_aix
         || cgcx.opts.target_triple.triple().starts_with("wasm")
@@ -932,13 +991,7 @@ unsafe fn embed_bitcode(
         );
         llvm::LLVMSetInitializer(llglobal, llconst);
 
-        let section = if is_apple {
-            "__LLVM,__bitcode\0"
-        } else if is_aix {
-            ".ipa\0"
-        } else {
-            ".llvmbc\0"
-        };
+        let section = bitcode_section_name(cgcx);
         llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
         llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
         llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 97a99e51056..bda287d782c 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,13 +1,14 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::coverageinfo::ffi::{Counter, CounterExpression, CounterMappingRegion};
+use crate::coverageinfo::ffi::CounterMappingRegion;
+use crate::coverageinfo::map_data::FunctionCoverage;
 use crate::llvm;
 
 use rustc_codegen_ssa::traits::ConstMethods;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_llvm::RustString;
+use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
@@ -55,7 +56,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         return;
     }
 
-    let mut mapgen = CoverageMapGenerator::new(tcx);
+    let mut global_file_table = GlobalFileTable::new(tcx);
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
@@ -64,12 +65,9 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         let mangled_function_name = tcx.symbol_name(instance).name;
         let source_hash = function_coverage.source_hash();
         let is_used = function_coverage.is_used();
-        let (expressions, counter_regions) =
-            function_coverage.get_expressions_and_counter_regions();
 
-        let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
-            mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
-        });
+        let coverage_mapping_buffer =
+            encode_mappings_for_function(&mut global_file_table, &function_coverage);
 
         if coverage_mapping_buffer.is_empty() {
             if function_coverage.is_used() {
@@ -87,19 +85,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
     }
 
     // Encode all filenames referenced by counters/expressions in this module
-    let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
-        coverageinfo::write_filenames_section_to_buffer(
-            mapgen.filenames.iter().map(Symbol::as_str),
-            filenames_buffer,
-        );
-    });
+    let filenames_buffer = global_file_table.into_filenames_buffer();
 
     let filenames_size = filenames_buffer.len();
     let filenames_val = cx.const_bytes(&filenames_buffer);
     let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer);
 
     // Generate the LLVM IR representation of the coverage map and store it in a well-known global
-    let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val);
+    let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
 
     let covfun_section_name = coverageinfo::covfun_section_name(cx);
     for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
@@ -118,13 +111,13 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
     coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
 }
 
-struct CoverageMapGenerator {
-    filenames: FxIndexSet<Symbol>,
+struct GlobalFileTable {
+    global_file_table: FxIndexSet<Symbol>,
 }
 
-impl CoverageMapGenerator {
+impl GlobalFileTable {
     fn new(tcx: TyCtxt<'_>) -> Self {
-        let mut filenames = FxIndexSet::default();
+        let mut global_file_table = FxIndexSet::default();
         // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
         // requires setting the first filename to the compilation directory.
         // Since rustc generates coverage maps with relative paths, the
@@ -133,94 +126,114 @@ impl CoverageMapGenerator {
         let working_dir = Symbol::intern(
             &tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
         );
-        filenames.insert(working_dir);
-        Self { filenames }
+        global_file_table.insert(working_dir);
+        Self { global_file_table }
     }
 
-    /// Using the `expressions` and `counter_regions` collected for the current function, generate
-    /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
-    /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
-    /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
-    fn write_coverage_mapping<'a>(
-        &mut self,
-        expressions: Vec<CounterExpression>,
-        counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
-        coverage_mapping_buffer: &RustString,
-    ) {
-        let mut counter_regions = counter_regions.collect::<Vec<_>>();
-        if counter_regions.is_empty() {
-            return;
-        }
+    fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> u32 {
+        let (global_file_id, _) = self.global_file_table.insert_full(file_name);
+        global_file_id as u32
+    }
 
-        let mut virtual_file_mapping = Vec::new();
-        let mut mapping_regions = Vec::new();
-        let mut current_file_name = None;
-        let mut current_file_id = 0;
-
-        // Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
-        // by filename and position. Capture any new files to compute the `CounterMappingRegion`s
-        // `file_id` (indexing files referenced by the current function), and construct the
-        // function-specific `virtual_file_mapping` from `file_id` to its index in the module's
-        // `filenames` array.
-        counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
-        for (counter, region) in counter_regions {
-            let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
-            let same_file = current_file_name.is_some_and(|p| p == file_name);
-            if !same_file {
-                if current_file_name.is_some() {
-                    current_file_id += 1;
-                }
-                current_file_name = Some(file_name);
-                debug!("  file_id: {} = '{:?}'", current_file_id, file_name);
-                let (filenames_index, _) = self.filenames.insert_full(file_name);
-                virtual_file_mapping.push(filenames_index as u32);
-            }
-            debug!("Adding counter {:?} to map for {:?}", counter, region);
+    fn into_filenames_buffer(self) -> Vec<u8> {
+        // This method takes `self` so that the caller can't accidentally
+        // modify the original file table after encoding it into a buffer.
+
+        llvm::build_byte_buffer(|buffer| {
+            coverageinfo::write_filenames_section_to_buffer(
+                self.global_file_table.iter().map(Symbol::as_str),
+                buffer,
+            );
+        })
+    }
+}
+
+/// Using the expressions and counter regions collected for a single function,
+/// generate the variable-sized payload of its corresponding `__llvm_covfun`
+/// entry. The payload is returned as a vector of bytes.
+///
+/// Newly-encountered filenames will be added to the global file table.
+fn encode_mappings_for_function(
+    global_file_table: &mut GlobalFileTable,
+    function_coverage: &FunctionCoverage<'_>,
+) -> Vec<u8> {
+    let (expressions, counter_regions) = function_coverage.get_expressions_and_counter_regions();
+
+    let mut counter_regions = counter_regions.collect::<Vec<_>>();
+    if counter_regions.is_empty() {
+        return Vec::new();
+    }
+
+    let mut virtual_file_mapping = IndexVec::<u32, u32>::new();
+    let mut mapping_regions = Vec::with_capacity(counter_regions.len());
+
+    // Sort the list of (counter, region) mapping pairs by region, so that they
+    // can be grouped by filename. Prepare file IDs for each filename, and
+    // prepare the mapping data so that we can pass it through FFI to LLVM.
+    counter_regions.sort_by_key(|(_counter, region)| *region);
+    for counter_regions_for_file in
+        counter_regions.group_by(|(_, a), (_, b)| a.file_name == b.file_name)
+    {
+        // Look up (or allocate) the global file ID for this filename.
+        let file_name = counter_regions_for_file[0].1.file_name;
+        let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
+
+        // Associate that global file ID with a local file ID for this function.
+        let local_file_id: u32 = virtual_file_mapping.push(global_file_id);
+        debug!("  file id: local {local_file_id} => global {global_file_id} = '{file_name:?}'");
+
+        // For each counter/region pair in this function+file, convert it to a
+        // form suitable for FFI.
+        for &(counter, region) in counter_regions_for_file {
+            let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = *region;
+
+            debug!("Adding counter {counter:?} to map for {region:?}");
             mapping_regions.push(CounterMappingRegion::code_region(
                 counter,
-                current_file_id,
+                local_file_id,
                 start_line,
                 start_col,
                 end_line,
                 end_col,
             ));
         }
+    }
 
-        // Encode and append the current function's coverage mapping data
+    // Encode the function's coverage mappings into a buffer.
+    llvm::build_byte_buffer(|buffer| {
         coverageinfo::write_mapping_to_buffer(
-            virtual_file_mapping,
+            virtual_file_mapping.raw,
             expressions,
             mapping_regions,
-            coverage_mapping_buffer,
+            buffer,
         );
-    }
+    })
+}
 
-    /// Construct coverage map header and the array of function records, and combine them into the
-    /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
-    /// specific, well-known section and name.
-    fn generate_coverage_map<'ll>(
-        self,
-        cx: &CodegenCx<'ll, '_>,
-        version: u32,
-        filenames_size: usize,
-        filenames_val: &'ll llvm::Value,
-    ) -> &'ll llvm::Value {
-        debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
-
-        // Create the coverage data header (Note, fields 0 and 2 are now always zero,
-        // as of `llvm::coverage::CovMapVersion::Version4`.)
-        let zero_was_n_records_val = cx.const_u32(0);
-        let filenames_size_val = cx.const_u32(filenames_size as u32);
-        let zero_was_coverage_size_val = cx.const_u32(0);
-        let version_val = cx.const_u32(version);
-        let cov_data_header_val = cx.const_struct(
-            &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
-            /*packed=*/ false,
-        );
+/// Construct coverage map header and the array of function records, and combine them into the
+/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
+/// specific, well-known section and name.
+fn generate_coverage_map<'ll>(
+    cx: &CodegenCx<'ll, '_>,
+    version: u32,
+    filenames_size: usize,
+    filenames_val: &'ll llvm::Value,
+) -> &'ll llvm::Value {
+    debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
+
+    // Create the coverage data header (Note, fields 0 and 2 are now always zero,
+    // as of `llvm::coverage::CovMapVersion::Version4`.)
+    let zero_was_n_records_val = cx.const_u32(0);
+    let filenames_size_val = cx.const_u32(filenames_size as u32);
+    let zero_was_coverage_size_val = cx.const_u32(0);
+    let version_val = cx.const_u32(version);
+    let cov_data_header_val = cx.const_struct(
+        &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
+        /*packed=*/ false,
+    );
 
-        // Create the complete LLVM coverage data value to add to the LLVM IR
-        cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
-    }
+    // Create the complete LLVM coverage data value to add to the LLVM IR
+    cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
 }
 
 /// Construct a function record and combine it with the function's coverage mapping data.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index ebf4ee4164f..5ca2942ac4e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
-    debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
+    debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
 ) {
     // Find all scopes with variables defined in them.
     let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
@@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>(
     instance: Instance<'tcx>,
     mir: &Body<'tcx>,
     variables: &Option<BitSet<SourceScope>>,
-    debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
+    debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
     instantiated: &mut BitSet<SourceScope>,
     scope: SourceScope,
 ) {
@@ -86,7 +86,7 @@ fn make_mir_scope<'ll, 'tcx>(
     let loc = cx.lookup_debug_loc(scope_data.span.lo());
     let file_metadata = file_metadata(cx, &loc.file);
 
-    let dbg_scope = match scope_data.inlined {
+    let parent_dbg_scope = match scope_data.inlined {
         Some((callee, _)) => {
             // FIXME(eddyb) this would be `self.monomorphize(&callee)`
             // if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
@@ -95,18 +95,22 @@ fn make_mir_scope<'ll, 'tcx>(
                 ty::ParamEnv::reveal_all(),
                 ty::EarlyBinder::bind(callee),
             );
-            let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
-            cx.dbg_scope_fn(callee, callee_fn_abi, None)
+            debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
+                let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
+                cx.dbg_scope_fn(callee, callee_fn_abi, None)
+            })
         }
-        None => unsafe {
-            llvm::LLVMRustDIBuilderCreateLexicalBlock(
-                DIB(cx),
-                parent_scope.dbg_scope,
-                file_metadata,
-                loc.line,
-                loc.col,
-            )
-        },
+        None => parent_scope.dbg_scope,
+    };
+
+    let dbg_scope = unsafe {
+        llvm::LLVMRustDIBuilderCreateLexicalBlock(
+            DIB(cx),
+            parent_dbg_scope,
+            file_metadata,
+            loc.line,
+            loc.col,
+        )
     };
 
     let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 2301f66dc28..52481a1090c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -263,7 +263,7 @@ impl CodegenCx<'_, '_> {
     pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
         let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
             Ok(SourceFileAndLine { sf: file, line }) => {
-                let line_pos = file.lines(|lines| lines[line]);
+                let line_pos = file.lines()[line];
 
                 // Use 1-based indexing.
                 let line = (line + 1) as u32;
@@ -292,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         llfn: &'ll Value,
         mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
+    ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
         if self.sess().opts.debuginfo == DebugInfo::None {
             return None;
         }
@@ -304,8 +304,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
         };
-        let mut fn_debug_context =
-            FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
+        let mut fn_debug_context = FunctionDebugContext {
+            scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
+            inlined_function_scopes: Default::default(),
+        };
 
         // Fill in all the scopes, with the information from the MIR body.
         compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index fced6d504d2..264c273ba30 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> {
 pub(crate) struct CopyBitcode {
     pub err: std::io::Error,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_debuginfo_compression)]
+pub struct UnknownCompression {
+    pub algorithm: &'static str,
+}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index d283299ac46..ac199624e34 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
+#![feature(slice_group_by)]
 #![feature(impl_trait_in_assoc_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 01cbf7d3b11..2ebfdae39e8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2131,8 +2131,12 @@ extern "C" {
         RelaxELFRelocations: bool,
         UseInitArray: bool,
         SplitDwarfFile: *const c_char,
+        DebugInfoCompression: *const c_char,
         ForceEmulatedTls: bool,
+        ArgsCstrBuff: *const c_char,
+        ArgsCstrBuffLen: usize,
     ) -> Option<&'static mut TargetMachine>;
+
     pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
     pub fn LLVMRustAddLibraryInfo<'a>(
         PM: &PassManager<'a>,
@@ -2319,6 +2323,12 @@ extern "C" {
         len: usize,
         out_len: &mut usize,
     ) -> *const u8;
+    pub fn LLVMRustGetSliceFromObjectDataByName(
+        data: *const u8,
+        len: usize,
+        name: *const u8,
+        out_len: &mut usize,
+    ) -> *const u8;
 
     pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
     pub fn LLVMRustLinkerAdd(
@@ -2357,6 +2367,10 @@ extern "C" {
 
     pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
 
+    pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;
+
+    pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;
+
     pub fn LLVMRustGetSymbols(
         buf_ptr: *const u8,
         buf_len: usize,
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index f485af00bca..3bf98c46dea 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -343,6 +343,12 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
     pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
 
+    /// All commandline args used to invoke the compiler, with @file args fully expanded.
+    /// This will only be used within debug info, e.g. in the pdb file on windows
+    /// This is mainly useful for other tools that reads that debuginfo to figure out
+    /// how to call the compiler with the same arguments.
+    pub expanded_args: Vec<String>,
+
     /// Handler to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     /// LLVM optimizations for which we want to print remarks.
@@ -1108,6 +1114,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
         cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
         coordinator_send,
+        expanded_args: tcx.sess.expanded_args.clone(),
         diag_emitter: shared_emitter.clone(),
         output_filenames: tcx.output_filenames(()).clone(),
         regular_module_config: regular_config,
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 526c16a59de..ac705a5f35c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -1,10 +1,12 @@
 use crate::traits::*;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::Instance;
 use rustc_middle::ty::Ty;
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
@@ -17,10 +19,13 @@ use super::{FunctionCx, LocalRef};
 
 use std::ops::Range;
 
-pub struct FunctionDebugContext<S, L> {
+pub struct FunctionDebugContext<'tcx, S, L> {
+    /// Maps from source code to the corresponding debug info scope.
     pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
-}
 
+    /// Maps from an inlined function to its debug info declaration.
+    pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
+}
 #[derive(Copy, Clone)]
 pub enum VariableKind {
     ArgumentVariable(usize /*index*/),
@@ -484,54 +489,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 None
             };
 
-            let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
-                let (var_ty, var_kind) = match var.value {
+            let var_ty = if let Some(ref fragment) = var.composite {
+                self.monomorphize(fragment.ty)
+            } else {
+                match var.value {
                     mir::VarDebugInfoContents::Place(place) => {
-                        let var_ty = self.monomorphized_place_ty(place.as_ref());
-                        let var_kind = if let Some(arg_index) = var.argument_index
-                            && place.projection.is_empty()
-                        {
-                            let arg_index = arg_index as usize;
-                            if target_is_msvc {
-                                // ScalarPair parameters are spilled to the stack so they need to
-                                // be marked as a `LocalVariable` for MSVC debuggers to visualize
-                                // their data correctly. (See #81894 & #88625)
-                                let var_ty_layout = self.cx.layout_of(var_ty);
-                                if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
-                                    VariableKind::LocalVariable
-                                } else {
-                                    VariableKind::ArgumentVariable(arg_index)
-                                }
-                            } else {
-                                // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
-                                // offset in closures to account for the hidden environment?
-                                VariableKind::ArgumentVariable(arg_index)
-                            }
-                        } else {
-                            VariableKind::LocalVariable
-                        };
-                        (var_ty, var_kind)
-                    }
-                    mir::VarDebugInfoContents::Const(c) => {
-                        let ty = self.monomorphize(c.ty());
-                        (ty, VariableKind::LocalVariable)
+                        self.monomorphized_place_ty(place.as_ref())
                     }
-                    mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
-                        let ty = self.monomorphize(ty);
-                        (ty, VariableKind::LocalVariable)
+                    mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
+                }
+            };
+
+            let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
+                let var_kind = if let Some(arg_index) = var.argument_index
+                    && var.composite.is_none()
+                    && let mir::VarDebugInfoContents::Place(place) = var.value
+                    && place.projection.is_empty()
+                {
+                    let arg_index = arg_index as usize;
+                    if target_is_msvc {
+                        // ScalarPair parameters are spilled to the stack so they need to
+                        // be marked as a `LocalVariable` for MSVC debuggers to visualize
+                        // their data correctly. (See #81894 & #88625)
+                        let var_ty_layout = self.cx.layout_of(var_ty);
+                        if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
+                            VariableKind::LocalVariable
+                        } else {
+                            VariableKind::ArgumentVariable(arg_index)
+                        }
+                    } else {
+                        // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
+                        // offset in closures to account for the hidden environment?
+                        VariableKind::ArgumentVariable(arg_index)
                     }
+                } else {
+                    VariableKind::LocalVariable
                 };
 
                 self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
             });
 
+            let fragment = if let Some(ref fragment) = var.composite {
+                let var_layout = self.cx.layout_of(var_ty);
+
+                let mut fragment_start = Size::ZERO;
+                let mut fragment_layout = var_layout;
+
+                for elem in &fragment.projection {
+                    match *elem {
+                        mir::ProjectionElem::Field(field, _) => {
+                            let i = field.index();
+                            fragment_start += fragment_layout.fields.offset(i);
+                            fragment_layout = fragment_layout.field(self.cx, i);
+                        }
+                        _ => span_bug!(
+                            var.source_info.span,
+                            "unsupported fragment projection `{:?}`",
+                            elem,
+                        ),
+                    }
+                }
+
+                if fragment_layout.size == Size::ZERO {
+                    // Fragment is a ZST, so does not represent anything. Avoid generating anything
+                    // as this may conflict with a fragment that covers the entire variable.
+                    continue;
+                } else if fragment_layout.size == var_layout.size {
+                    // Fragment covers entire variable, so as far as
+                    // DWARF is concerned, it's not really a fragment.
+                    None
+                } else {
+                    Some(fragment_start..fragment_start + fragment_layout.size)
+                }
+            } else {
+                None
+            };
+
             match var.value {
                 mir::VarDebugInfoContents::Place(place) => {
                     per_local[place.local].push(PerLocalVarDebugInfo {
                         name: var.name,
                         source_info: var.source_info,
                         dbg_var,
-                        fragment: None,
+                        fragment,
                         projection: place.projection,
                     });
                 }
@@ -547,51 +587,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bx,
                             );
 
-                            bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
-                        }
-                    }
-                }
-                mir::VarDebugInfoContents::Composite { ty, ref fragments } => {
-                    let var_ty = self.monomorphize(ty);
-                    let var_layout = self.cx.layout_of(var_ty);
-                    for fragment in fragments {
-                        let mut fragment_start = Size::ZERO;
-                        let mut fragment_layout = var_layout;
-
-                        for elem in &fragment.projection {
-                            match *elem {
-                                mir::ProjectionElem::Field(field, _) => {
-                                    let i = field.index();
-                                    fragment_start += fragment_layout.fields.offset(i);
-                                    fragment_layout = fragment_layout.field(self.cx, i);
-                                }
-                                _ => span_bug!(
-                                    var.source_info.span,
-                                    "unsupported fragment projection `{:?}`",
-                                    elem,
-                                ),
-                            }
+                            bx.dbg_var_addr(
+                                dbg_var,
+                                dbg_loc,
+                                base.llval,
+                                Size::ZERO,
+                                &[],
+                                fragment,
+                            );
                         }
-
-                        let place = fragment.contents;
-                        let fragment = if fragment_layout.size == Size::ZERO {
-                            // Fragment is a ZST, so does not represent anything.
-                            continue;
-                        } else if fragment_layout.size == var_layout.size {
-                            // Fragment covers entire variable, so as far as
-                            // DWARF is concerned, it's not really a fragment.
-                            None
-                        } else {
-                            Some(fragment_start..fragment_start + fragment_layout.size)
-                        };
-
-                        per_local[place.local].push(PerLocalVarDebugInfo {
-                            name: var.name,
-                            source_info: var.source_info,
-                            dbg_var,
-                            fragment,
-                            projection: place.projection,
-                        });
                     }
                 }
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index bf937c2fc7c..c4408f2db4c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 
     mir: &'tcx mir::Body<'tcx>,
 
-    debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
+    debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>,
 
     llfn: Bx::Function,
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index 63fecaf34fd..4acc0ea076c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         llfn: Self::Function,
         mir: &mir::Body<'tcx>,
-    ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
+    ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>;
 
     // FIXME(eddyb) find a common convention for all of the debuginfo-related
     // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c74fed0e47f..c3c6cbe3991 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -482,6 +482,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
         use UndefinedBehaviorInfo::*;
         match self {
             Ub(msg) => msg.clone().into(),
+            Custom(x) => (x.msg)(),
+            ValidationError(e) => e.diagnostic_message(),
+
             Unreachable => const_eval_unreachable,
             BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
             DivisionByZero => const_eval_division_by_zero,
@@ -513,8 +516,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
             UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
             UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
-            ValidationError(e) => e.diagnostic_message(),
-            Custom(x) => (x.msg)(),
+            AbiMismatchArgument { .. } => const_eval_incompatible_types,
+            AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
         }
     }
 
@@ -525,8 +528,15 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
     ) {
         use UndefinedBehaviorInfo::*;
         match self {
-            Ub(_)
-            | Unreachable
+            Ub(_) => {}
+            Custom(custom) => {
+                (custom.add_args)(&mut |name, value| {
+                    builder.set_arg(name, value);
+                });
+            }
+            ValidationError(e) => e.add_args(handler, builder),
+
+            Unreachable
             | DivisionByZero
             | RemainderByZero
             | DivisionOverflow
@@ -593,11 +603,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                 builder.set_arg("target_size", info.target_size);
                 builder.set_arg("data_size", info.data_size);
             }
-            ValidationError(e) => e.add_args(handler, builder),
-            Custom(custom) => {
-                (custom.add_args)(&mut |name, value| {
-                    builder.set_arg(name, value);
-                });
+            AbiMismatchArgument { caller_ty, callee_ty }
+            | AbiMismatchReturn { caller_ty, callee_ty } => {
+                builder.set_arg("caller_ty", caller_ty.to_string());
+                builder.set_arg("callee_ty", callee_ty.to_string());
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index d8ad82d3da0..90f2b470179 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -796,6 +796,13 @@ where
         dest: &impl Writeable<'tcx, M::Provenance>,
         allow_transmute: bool,
     ) -> InterpResult<'tcx> {
+        // Generally for transmutation, data must be valid both at the old and new type.
+        // But if the types are the same, the 2nd validation below suffices.
+        if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) {
+            self.validate_operand(&src.to_op(self)?)?;
+        }
+
+        // Do the actual copy.
         self.copy_op_no_validate(src, dest, allow_transmute)?;
 
         if M::enforce_validity(self, dest.layout()) {
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index bc4edf1c4b6..7e22981542e 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -6,12 +6,16 @@ use rustc_middle::{
     mir,
     ty::{
         self,
-        layout::{FnAbiOf, LayoutOf, TyAndLayout},
-        Instance, Ty,
+        layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout},
+        AdtDef, Instance, Ty,
     },
 };
-use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode};
+use rustc_span::sym;
 use rustc_target::abi::{self, FieldIdx};
+use rustc_target::abi::{
+    call::{ArgAbi, FnAbi, PassMode},
+    Integer,
+};
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -255,9 +259,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Find the wrapped inner type of a transparent wrapper.
     /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
-    fn unfold_transparent(&self, layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx> {
+    ///
+    /// We work with `TyAndLayout` here since that makes it much easier to iterate over all fields.
+    fn unfold_transparent(
+        &self,
+        layout: TyAndLayout<'tcx>,
+        may_unfold: impl Fn(AdtDef<'tcx>) -> bool,
+    ) -> TyAndLayout<'tcx> {
         match layout.ty.kind() {
-            ty::Adt(adt_def, _) if adt_def.repr().transparent() => {
+            ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => {
                 assert!(!adt_def.is_enum());
                 // Find the non-1-ZST field.
                 let mut non_1zst_fields = (0..layout.fields.count()).filter_map(|idx| {
@@ -271,131 +281,157 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 );
 
                 // Found it!
-                self.unfold_transparent(first)
+                self.unfold_transparent(first, may_unfold)
             }
             // Not a transparent type, no further unfolding.
             _ => layout,
         }
     }
 
+    /// Unwrap types that are guaranteed a null-pointer-optimization
+    fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
+        // Check if this is `Option` wrapping some type.
+        let inner = match layout.ty.kind() {
+            ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => {
+                args[0].as_type().unwrap()
+            }
+            _ => {
+                // Not an `Option`.
+                return Ok(layout);
+            }
+        };
+        let inner = self.layout_of(inner)?;
+        // Check if the inner type is one of the NPO-guaranteed ones.
+        // For that we first unpeel transparent *structs* (but not unions).
+        let is_npo = |def: AdtDef<'tcx>| {
+            self.tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
+        };
+        let inner = self.unfold_transparent(inner, /* may_unfold */ |def| {
+            // Stop at NPO tpyes so that we don't miss that attribute in the check below!
+            def.is_struct() && !is_npo(def)
+        });
+        Ok(match inner.ty.kind() {
+            ty::Ref(..) | ty::FnPtr(..) => {
+                // Option<&T> behaves like &T, and same for fn()
+                inner
+            }
+            ty::Adt(def, _) if is_npo(*def) => {
+                // Once we found a `nonnull_optimization_guaranteed` type, further strip off
+                // newtype structs from it to find the underlying ABI type.
+                self.unfold_transparent(inner, /* may_unfold */ |def| def.is_struct())
+            }
+            _ => {
+                // Everything else we do not unfold.
+                layout
+            }
+        })
+    }
+
     /// Check if these two layouts look like they are fn-ABI-compatible.
     /// (We also compare the `PassMode`, so this doesn't have to check everything. But it turns out
     /// that only checking the `PassMode` is insufficient.)
     fn layout_compat(
         &self,
-        caller_layout: TyAndLayout<'tcx>,
-        callee_layout: TyAndLayout<'tcx>,
-    ) -> bool {
-        if caller_layout.ty == callee_layout.ty {
-            // Fast path: equal types are definitely compatible.
-            return true;
+        caller: TyAndLayout<'tcx>,
+        callee: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, bool> {
+        // Fast path: equal types are definitely compatible.
+        if caller.ty == callee.ty {
+            return Ok(true);
         }
-
-        match (caller_layout.abi, callee_layout.abi) {
-            // If both sides have Scalar/Vector/ScalarPair ABI, we can easily directly compare them.
-            // Different valid ranges are okay (the validity check will complain if this leads to
-            // invalid transmutes). Different signs are *not* okay on some targets (e.g. `extern
-            // "C"` on `s390x` where small integers are passed zero/sign-extended in large
-            // registers), so we generally reject them to increase portability.
-            // NOTE: this is *not* a stable guarantee! It just reflects a property of our current
-            // ABIs. It's also fragile; the same pair of types might be considered ABI-compatible
-            // when used directly by-value but not considered compatible as a struct field or array
-            // element.
-            (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => {
-                caller.primitive() == callee.primitive()
-            }
-            (
-                abi::Abi::Vector { element: caller_element, count: caller_count },
-                abi::Abi::Vector { element: callee_element, count: callee_count },
-            ) => {
-                caller_element.primitive() == callee_element.primitive()
-                    && caller_count == callee_count
-            }
-            (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => {
-                caller1.primitive() == callee1.primitive()
-                    && caller2.primitive() == callee2.primitive()
-            }
-            (abi::Abi::Aggregate { .. }, abi::Abi::Aggregate { .. }) => {
-                // Aggregates are compatible only if they newtype-wrap the same type, or if they are both 1-ZST.
-                // (The latter part is needed to ensure e.g. that `struct Zst` is compatible with `struct Wrap((), Zst)`.)
-                // This is conservative, but also means that our check isn't quite so heavily dependent on the `PassMode`,
-                // which means having ABI-compatibility on one target is much more likely to imply compatibility for other targets.
-                if caller_layout.is_1zst() || callee_layout.is_1zst() {
-                    // If either is a 1-ZST, both must be.
-                    caller_layout.is_1zst() && callee_layout.is_1zst()
-                } else {
-                    // Neither is a 1-ZST, so we can check what they are wrapping.
-                    self.unfold_transparent(caller_layout).ty
-                        == self.unfold_transparent(callee_layout).ty
+        // 1-ZST are compatible with all 1-ZST (and with nothing else).
+        if caller.is_1zst() || callee.is_1zst() {
+            return Ok(caller.is_1zst() && callee.is_1zst());
+        }
+        // Unfold newtypes and NPO optimizations.
+        let unfold = |layout: TyAndLayout<'tcx>| {
+            self.unfold_npo(self.unfold_transparent(layout, /* may_unfold */ |_def| true))
+        };
+        let caller = unfold(caller)?;
+        let callee = unfold(callee)?;
+        // Now see if these inner types are compatible.
+
+        // Compatible pointer types. For thin pointers, we have to accept even non-`repr(transparent)`
+        // things as compatible due to `DispatchFromDyn`. For instance, `Rc<i32>` and `*mut i32`
+        // must be compatible. So we just accept everything with Pointer ABI as compatible,
+        // even if this will accept some code that is not stably guaranteed to work.
+        // This also handles function pointers.
+        let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.abi {
+            abi::Abi::Scalar(s) => match s.primitive() {
+                abi::Primitive::Pointer(addr_space) => Some(addr_space),
+                _ => None,
+            },
+            _ => None,
+        };
+        if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) {
+            return Ok(caller == callee);
+        }
+        // For wide pointers we have to get the pointee type.
+        let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option<Ty<'tcx>>> {
+            // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`.
+            Ok(Some(match ty.kind() {
+                ty::Ref(_, ty, _) => *ty,
+                ty::RawPtr(mt) => mt.ty,
+                // We should only accept `Box` with the default allocator.
+                // It's hard to test for that though so we accept every 1-ZST allocator.
+                ty::Adt(def, args)
+                    if def.is_box()
+                        && self.layout_of(args[1].expect_ty()).is_ok_and(|l| l.is_1zst()) =>
+                {
+                    args[0].expect_ty()
                 }
-            }
-            // What remains is `Abi::Uninhabited` (which can never be passed anyway) and
-            // mismatching ABIs, that should all be rejected.
-            _ => false,
+                _ => return Ok(None),
+            }))
+        };
+        if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) {
+            // This is okay if they have the same metadata type.
+            let meta_ty = |ty: Ty<'tcx>| {
+                let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, |ty| ty);
+                assert!(
+                    !only_if_sized,
+                    "there should be no more 'maybe has that metadata' types during interpretation"
+                );
+                meta
+            };
+            return Ok(meta_ty(caller) == meta_ty(callee));
         }
+
+        // Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
+        let int_ty = |ty: Ty<'tcx>| {
+            Some(match ty.kind() {
+                ty::Int(ity) => (Integer::from_int_ty(&self.tcx, *ity), /* signed */ true),
+                ty::Uint(uty) => (Integer::from_uint_ty(&self.tcx, *uty), /* signed */ false),
+                _ => return None,
+            })
+        };
+        if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) {
+            // This is okay if they are the same integer type.
+            return Ok(caller == callee);
+        }
+
+        // Fall back to exact equality.
+        // FIXME: We are missing the rules for "repr(C) wrapping compatible types".
+        Ok(caller == callee)
     }
 
     fn check_argument_compat(
         &self,
         caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
         callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
-    ) -> bool {
-        // When comparing the PassMode, we have to be smart about comparing the attributes.
-        let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| {
-            // There's only one regular attribute that matters for the call ABI: InReg.
-            // Everything else is things like noalias, dereferenceable, nonnull, ...
-            // (This also applies to pointee_size, pointee_align.)
-            if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg)
-            {
-                return false;
-            }
-            // We also compare the sign extension mode -- this could let the callee make assumptions
-            // about bits that conceptually were not even passed.
-            if a1.arg_ext != a2.arg_ext {
-                return false;
-            }
-            return true;
-        };
-        let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) {
-            (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type
-            (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2),
-            (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => {
-                arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2)
-            }
-            (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1 == c2 && pad1 == pad2,
-            (
-                PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
-                PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
-            ) => arg_attr_compat(a1, a2) && s1 == s2,
-            (
-                PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 },
-                PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 },
-            ) => arg_attr_compat(a1, a2) && arg_attr_compat(e1, e2) && s1 == s2,
-            _ => false,
-        };
-
-        // Ideally `PassMode` would capture everything there is about argument passing, but that is
-        // not the case: in `FnAbi::llvm_type`, also parts of the layout and type information are
-        // used. So we need to check that *both* sufficiently agree to ensures the arguments are
-        // compatible.
-        // For instance, `layout_compat` is needed to reject `i32` vs `f32`, which is not reflected
-        // in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`, which have the same
-        // `abi::Primitive` but different `arg_ext`.
-        if self.layout_compat(caller_abi.layout, callee_abi.layout) && mode_compat() {
-            // Something went very wrong if our checks don't even imply that the layout is the same.
-            assert!(
-                caller_abi.layout.size == callee_abi.layout.size
-                    && caller_abi.layout.align.abi == callee_abi.layout.align.abi
-                    && caller_abi.layout.is_sized() == callee_abi.layout.is_sized()
-            );
-            return true;
+    ) -> InterpResult<'tcx, bool> {
+        // We do not want to accept things as ABI-compatible that just "happen to be" compatible on the current target,
+        // so we implement a type-based check that reflects the guaranteed rules for ABI compatibility.
+        if self.layout_compat(caller_abi.layout, callee_abi.layout)? {
+            // Ensure that our checks imply actual ABI compatibility for this concrete call.
+            assert!(caller_abi.eq_abi(&callee_abi));
+            return Ok(true);
         } else {
             trace!(
                 "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
                 caller_abi,
                 callee_abi
             );
-            return false;
+            return Ok(false);
         }
     }
 
@@ -414,6 +450,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         'tcx: 'x,
         'tcx: 'y,
     {
+        assert_eq!(callee_ty, callee_abi.layout.ty);
         if matches!(callee_abi.mode, PassMode::Ignore) {
             // This one is skipped. Still must be made live though!
             if !already_live {
@@ -425,15 +462,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let Some((caller_arg, caller_abi)) = caller_args.next() else {
             throw_ub_custom!(fluent::const_eval_not_enough_caller_args);
         };
+        assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout);
+        // Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are
+        // equal; in closures the types sometimes differ. We just hope that `caller_abi` is the
+        // right type to print to the user.
+
         // Check compatibility
-        if !self.check_argument_compat(caller_abi, callee_abi) {
-            let callee_ty = format!("{}", callee_ty);
-            let caller_ty = format!("{}", caller_arg.layout().ty);
-            throw_ub_custom!(
-                fluent::const_eval_incompatible_types,
-                callee_ty = callee_ty,
-                caller_ty = caller_ty,
-            )
+        if !self.check_argument_compat(caller_abi, callee_abi)? {
+            throw_ub!(AbiMismatchArgument {
+                caller_ty: caller_abi.layout.ty,
+                callee_ty: callee_abi.layout.ty
+            });
         }
         // We work with a copy of the argument for now; if this is in-place argument passing, we
         // will later protect the source it comes from. This means the callee cannot observe if we
@@ -637,7 +676,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // taking into account the `spread_arg`. If we could write
                     // this is a single iterator (that handles `spread_arg`), then
                     // `pass_argument` would be the loop body. It takes care to
-                    // not advance `caller_iter` for ZSTs.
+                    // not advance `caller_iter` for ignored arguments.
                     let mut callee_args_abis = callee_fn_abi.args.iter();
                     for local in body.args_iter() {
                         // Construct the destination place for this argument. At this point all
@@ -699,14 +738,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         throw_ub_custom!(fluent::const_eval_too_many_caller_args);
                     }
                     // Don't forget to check the return type!
-                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret) {
-                        let callee_ty = format!("{}", callee_fn_abi.ret.layout.ty);
-                        let caller_ty = format!("{}", caller_fn_abi.ret.layout.ty);
-                        throw_ub_custom!(
-                            fluent::const_eval_incompatible_return_types,
-                            callee_ty = callee_ty,
-                            caller_ty = caller_ty,
-                        )
+                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
+                        throw_ub!(AbiMismatchReturn {
+                            caller_ty: caller_fn_abi.ret.layout.ty,
+                            callee_ty: callee_fn_abi.ret.layout.ty
+                        });
                     }
                     // Ensure the return place is aligned and dereferenceable, and protect it for
                     // in-place return value passing.
@@ -728,7 +764,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Ok(()) => Ok(()),
                 }
             }
-            // cannot use the shim here, because that will only result in infinite recursion
+            // `InstanceDef::Virtual` does not have callable MIR. Calls to `Virtual` instances must be
+            // codegen'd / interpreted as virtual calls through the vtable.
             ty::InstanceDef::Virtual(def_id, idx) => {
                 let mut args = args.to_vec();
                 // We have to implement all "object safe receivers". So we have to go search for a
@@ -852,18 +889,26 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
 
                 // Adjust receiver argument. Layout can be any (thin) ptr.
+                let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
                 args[0] = FnArg::Copy(
                     ImmTy::from_immediate(
                         Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
-                        self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?,
+                        self.layout_of(receiver_ty)?,
                     )
                     .into(),
                 );
                 trace!("Patched receiver operand to {:#?}", args[0]);
+                // Need to also adjust the type in the ABI. Strangely, the layout there is actually
+                // already fine! Just the type is bogus. This is due to what `force_thin_self_ptr`
+                // does in `fn_abi_new_uncached`; supposedly, codegen relies on having the bogus
+                // type, so we just patch this up locally.
+                let mut caller_fn_abi = caller_fn_abi.clone();
+                caller_fn_abi.args[0].layout.ty = receiver_ty;
+
                 // recurse with concrete function
                 self.eval_fn_call(
                     FnVal::Instance(fn_inst),
-                    (caller_abi, caller_fn_abi),
+                    (caller_abi, &caller_fn_abi),
                     &args,
                     with_caller_location,
                     destination,
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 770c3f7f02c..2f5f2ad6534 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -6,13 +6,7 @@ use rustc_index::IndexVec;
 use rustc_infer::traits::Reveal;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{
-    traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
-    MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
-    ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
-    Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo,
-    VarDebugInfoContents, START_BLOCK,
-};
+use rustc_middle::mir::*;
 use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -757,37 +751,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
     }
 
     fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
-        let check_place = |this: &mut Self, place: Place<'_>| {
-            if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
-                this.fail(
+        if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite {
+            if ty.is_union() || ty.is_enum() {
+                self.fail(
                     START_BLOCK.start_location(),
-                    format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
+                    format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name),
                 );
             }
-        };
+            if projection.is_empty() {
+                self.fail(
+                    START_BLOCK.start_location(),
+                    format!("invalid empty projection in debuginfo for {:?}", debuginfo.name),
+                );
+            }
+            if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
+                self.fail(
+                    START_BLOCK.start_location(),
+                    format!(
+                        "illegal projection {:?} in debuginfo for {:?}",
+                        projection, debuginfo.name
+                    ),
+                );
+            }
+        }
         match debuginfo.value {
             VarDebugInfoContents::Const(_) => {}
             VarDebugInfoContents::Place(place) => {
-                check_place(self, place);
-            }
-            VarDebugInfoContents::Composite { ty, ref fragments } => {
-                for f in fragments {
-                    check_place(self, f.contents);
-                    if ty.is_union() || ty.is_enum() {
-                        self.fail(
-                            START_BLOCK.start_location(),
-                            format!("invalid type {ty:?} for composite debuginfo"),
-                        );
-                    }
-                    if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
-                        self.fail(
-                            START_BLOCK.start_location(),
-                            format!(
-                                "illegal projection {:?} in debuginfo for {:?}",
-                                f.projection, debuginfo.name
-                            ),
-                        );
-                    }
+                if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
+                    self.fail(
+                        START_BLOCK.start_location(),
+                        format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 0f769c1f3bf..29516fffd6a 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,7 +1,7 @@
 use crate::fx::{FxHashMap, FxHasher};
 #[cfg(parallel_compiler)]
 use crate::sync::{is_dyn_thread_safe, CacheAligned};
-use crate::sync::{Lock, LockGuard};
+use crate::sync::{Lock, LockGuard, Mode};
 #[cfg(parallel_compiler)]
 use itertools::Either;
 use std::borrow::Borrow;
@@ -73,6 +73,56 @@ impl<T> Sharded<T> {
         }
     }
 
+    /// The shard is selected by hashing `val` with `FxHasher`.
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_value<K: Hash + ?Sized>(&self, _val: &K) -> LockGuard<'_, T> {
+        match self {
+            Self::Single(single) => {
+                // Syncronization is disabled so use the `lock_assume_no_sync` method optimized
+                // for that case.
+
+                // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
+                // `might_be_dyn_thread_safe` was also false.
+                unsafe { single.lock_assume(Mode::NoSync) }
+            }
+            #[cfg(parallel_compiler)]
+            Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)),
+        }
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_hash(&self, hash: u64) -> LockGuard<'_, T> {
+        self.lock_shard_by_index(get_shard_hash(hash))
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn lock_shard_by_index(&self, _i: usize) -> LockGuard<'_, T> {
+        match self {
+            Self::Single(single) => {
+                // Syncronization is disabled so use the `lock_assume_no_sync` method optimized
+                // for that case.
+
+                // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
+                // `might_be_dyn_thread_safe` was also false.
+                unsafe { single.lock_assume(Mode::NoSync) }
+            }
+            #[cfg(parallel_compiler)]
+            Self::Shards(shards) => {
+                // Syncronization is enabled so use the `lock_assume_sync` method optimized
+                // for that case.
+
+                // SAFETY (get_unchecked): The index gets ANDed with the shard mask, ensuring it is
+                // always inbounds.
+                // SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating
+                // the lock thus `might_be_dyn_thread_safe` was also true.
+                unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) }
+            }
+        }
+    }
+
     #[inline]
     pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> {
         match self {
@@ -124,7 +174,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
         Q: Hash + Eq,
     {
         let hash = make_hash(value);
-        let mut shard = self.get_shard_by_hash(hash).lock();
+        let mut shard = self.lock_shard_by_hash(hash);
         let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value);
 
         match entry {
@@ -144,7 +194,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
         Q: Hash + Eq,
     {
         let hash = make_hash(&value);
-        let mut shard = self.get_shard_by_hash(hash).lock();
+        let mut shard = self.lock_shard_by_hash(hash);
         let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value);
 
         match entry {
@@ -166,7 +216,7 @@ pub trait IntoPointer {
 impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
     pub fn contains_pointer_to<T: Hash + IntoPointer>(&self, value: &T) -> bool {
         let hash = make_hash(&value);
-        let shard = self.get_shard_by_hash(hash).lock();
+        let shard = self.lock_shard_by_hash(hash);
         let value = value.into_pointer();
         shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some()
     }
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index a12889c5e2b..cca043ba0d1 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -46,7 +46,7 @@ use std::hash::{BuildHasher, Hash};
 use std::ops::{Deref, DerefMut};
 
 mod lock;
-pub use lock::{Lock, LockGuard};
+pub use lock::{Lock, LockGuard, Mode};
 
 mod worker_local;
 pub use worker_local::{Registry, WorkerLocal};
@@ -63,6 +63,9 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
 
 mod vec;
 
+mod freeze;
+pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
+
 mod mode {
     use super::Ordering;
     use std::sync::atomic::AtomicU8;
@@ -85,7 +88,6 @@ mod mode {
 
     // Whether thread safety might be enabled.
     #[inline]
-    #[cfg(parallel_compiler)]
     pub fn might_be_dyn_thread_safe() -> bool {
         DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE
     }
diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs
new file mode 100644
index 00000000000..466c44f59bb
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sync/freeze.rs
@@ -0,0 +1,200 @@
+use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard};
+#[cfg(parallel_compiler)]
+use crate::sync::{DynSend, DynSync};
+use std::{
+    cell::UnsafeCell,
+    intrinsics::likely,
+    marker::PhantomData,
+    ops::{Deref, DerefMut},
+    ptr::NonNull,
+    sync::atomic::Ordering,
+};
+
+/// A type which allows mutation using a lock until
+/// the value is frozen and can be accessed lock-free.
+///
+/// Unlike `RwLock`, it can be used to prevent mutation past a point.
+#[derive(Default)]
+pub struct FreezeLock<T> {
+    data: UnsafeCell<T>,
+    frozen: AtomicBool,
+
+    /// This lock protects writes to the `data` and `frozen` fields.
+    lock: RwLock<()>,
+}
+
+#[cfg(parallel_compiler)]
+unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {}
+
+impl<T> FreezeLock<T> {
+    #[inline]
+    pub fn new(value: T) -> Self {
+        Self::with(value, false)
+    }
+
+    #[inline]
+    pub fn frozen(value: T) -> Self {
+        Self::with(value, true)
+    }
+
+    #[inline]
+    pub fn with(value: T, frozen: bool) -> Self {
+        Self {
+            data: UnsafeCell::new(value),
+            frozen: AtomicBool::new(frozen),
+            lock: RwLock::new(()),
+        }
+    }
+
+    /// Clones the inner value along with the frozen state.
+    #[inline]
+    pub fn clone(&self) -> Self
+    where
+        T: Clone,
+    {
+        let lock = self.read();
+        Self::with(lock.clone(), self.is_frozen())
+    }
+
+    #[inline]
+    pub fn is_frozen(&self) -> bool {
+        self.frozen.load(Ordering::Acquire)
+    }
+
+    /// Get the inner value if frozen.
+    #[inline]
+    pub fn get(&self) -> Option<&T> {
+        if likely(self.frozen.load(Ordering::Acquire)) {
+            // SAFETY: This is frozen so the data cannot be modified.
+            unsafe { Some(&*self.data.get()) }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    pub fn read(&self) -> FreezeReadGuard<'_, T> {
+        FreezeReadGuard {
+            _lock_guard: if self.frozen.load(Ordering::Acquire) {
+                None
+            } else {
+                Some(self.lock.read())
+            },
+            data: unsafe { NonNull::new_unchecked(self.data.get()) },
+        }
+    }
+
+    #[inline]
+    pub fn borrow(&self) -> FreezeReadGuard<'_, T> {
+        self.read()
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn write(&self) -> FreezeWriteGuard<'_, T> {
+        self.try_write().expect("still mutable")
+    }
+
+    #[inline]
+    pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> {
+        let _lock_guard = self.lock.write();
+        // Use relaxed ordering since we're in the write lock.
+        if self.frozen.load(Ordering::Relaxed) {
+            None
+        } else {
+            Some(FreezeWriteGuard {
+                _lock_guard,
+                data: unsafe { NonNull::new_unchecked(self.data.get()) },
+                frozen: &self.frozen,
+                marker: PhantomData,
+            })
+        }
+    }
+
+    #[inline]
+    pub fn freeze(&self) -> &T {
+        if !self.frozen.load(Ordering::Acquire) {
+            // Get the lock to ensure no concurrent writes and that we release the latest write.
+            let _lock = self.lock.write();
+            self.frozen.store(true, Ordering::Release);
+        }
+
+        // SAFETY: This is frozen so the data cannot be modified and shared access is sound.
+        unsafe { &*self.data.get() }
+    }
+}
+
+/// A guard holding shared access to a `FreezeLock` which is in a locked state or frozen.
+#[must_use = "if unused the FreezeLock may immediately unlock"]
+pub struct FreezeReadGuard<'a, T: ?Sized> {
+    _lock_guard: Option<ReadGuard<'a, ()>>,
+    data: NonNull<T>,
+}
+
+impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &T {
+        // SAFETY: If the lock is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so
+        // this has shared access until the `FreezeReadGuard` is dropped. If the lock is frozen,
+        // the data cannot be modified and shared access is sound.
+        unsafe { &*self.data.as_ptr() }
+    }
+}
+
+impl<'a, T: ?Sized> FreezeReadGuard<'a, T> {
+    #[inline]
+    pub fn map<U: ?Sized>(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> {
+        FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard }
+    }
+}
+
+/// A guard holding mutable access to a `FreezeLock` which is in a locked state or frozen.
+#[must_use = "if unused the FreezeLock may immediately unlock"]
+pub struct FreezeWriteGuard<'a, T: ?Sized> {
+    _lock_guard: WriteGuard<'a, ()>,
+    frozen: &'a AtomicBool,
+    data: NonNull<T>,
+    marker: PhantomData<&'a mut T>,
+}
+
+impl<'a, T> FreezeWriteGuard<'a, T> {
+    pub fn freeze(self) -> &'a T {
+        self.frozen.store(true, Ordering::Release);
+
+        // SAFETY: This is frozen so the data cannot be modified and shared access is sound.
+        unsafe { &*self.data.as_ptr() }
+    }
+}
+
+impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> {
+    #[inline]
+    pub fn map<U: ?Sized>(
+        mut this: Self,
+        f: impl FnOnce(&mut T) -> &mut U,
+    ) -> FreezeWriteGuard<'a, U> {
+        FreezeWriteGuard {
+            data: NonNull::from(f(&mut *this)),
+            _lock_guard: this._lock_guard,
+            frozen: this.frozen,
+            marker: PhantomData,
+        }
+    }
+}
+
+impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &T {
+        // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has shared access.
+        unsafe { &*self.data.as_ptr() }
+    }
+}
+
+impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has mutable access.
+        unsafe { &mut *self.data.as_ptr() }
+    }
+}
diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs
index 62cd1b993de..339aebbf81a 100644
--- a/compiler/rustc_data_structures/src/sync/lock.rs
+++ b/compiler/rustc_data_structures/src/sync/lock.rs
@@ -3,224 +3,229 @@
 //!
 //! When `cfg(parallel_compiler)` is not set, the lock is instead a wrapper around `RefCell`.
 
-#[cfg(not(parallel_compiler))]
-use std::cell::RefCell;
-#[cfg(parallel_compiler)]
-use {
-    crate::cold_path,
-    crate::sync::DynSend,
-    crate::sync::DynSync,
-    parking_lot::lock_api::RawMutex,
-    std::cell::Cell,
-    std::cell::UnsafeCell,
-    std::fmt,
-    std::intrinsics::{likely, unlikely},
-    std::marker::PhantomData,
-    std::mem::ManuallyDrop,
-    std::ops::{Deref, DerefMut},
-};
+#![allow(dead_code)]
 
-#[cfg(not(parallel_compiler))]
-pub use std::cell::RefMut as LockGuard;
+use std::fmt;
 
+#[cfg(parallel_compiler)]
+pub use maybe_sync::*;
 #[cfg(not(parallel_compiler))]
-#[derive(Debug)]
-pub struct Lock<T>(RefCell<T>);
+pub use no_sync::*;
 
-#[cfg(not(parallel_compiler))]
-impl<T> Lock<T> {
-    #[inline(always)]
-    pub fn new(inner: T) -> Self {
-        Lock(RefCell::new(inner))
-    }
+#[derive(Clone, Copy, PartialEq)]
+pub enum Mode {
+    NoSync,
+    Sync,
+}
 
-    #[inline(always)]
-    pub fn into_inner(self) -> T {
-        self.0.into_inner()
+mod maybe_sync {
+    use super::Mode;
+    use crate::sync::mode;
+    #[cfg(parallel_compiler)]
+    use crate::sync::{DynSend, DynSync};
+    use parking_lot::lock_api::RawMutex as _;
+    use parking_lot::RawMutex;
+    use std::cell::Cell;
+    use std::cell::UnsafeCell;
+    use std::intrinsics::unlikely;
+    use std::marker::PhantomData;
+    use std::mem::ManuallyDrop;
+    use std::ops::{Deref, DerefMut};
+
+    /// A guard holding mutable access to a `Lock` which is in a locked state.
+    #[must_use = "if unused the Lock will immediately unlock"]
+    pub struct LockGuard<'a, T> {
+        lock: &'a Lock<T>,
+        marker: PhantomData<&'a mut T>,
+
+        /// The syncronization mode of the lock. This is explicitly passed to let LLVM relate it
+        /// to the original lock operation.
+        mode: Mode,
     }
 
-    #[inline(always)]
-    pub fn get_mut(&mut self) -> &mut T {
-        self.0.get_mut()
+    impl<'a, T: 'a> Deref for LockGuard<'a, T> {
+        type Target = T;
+        #[inline]
+        fn deref(&self) -> &T {
+            // SAFETY: We have shared access to the mutable access owned by this type,
+            // so we can give out a shared reference.
+            unsafe { &*self.lock.data.get() }
+        }
     }
 
-    #[inline(always)]
-    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-        self.0.try_borrow_mut().ok()
+    impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
+        #[inline]
+        fn deref_mut(&mut self) -> &mut T {
+            // SAFETY: We have mutable access to the data so we can give out a mutable reference.
+            unsafe { &mut *self.lock.data.get() }
+        }
     }
 
-    #[inline(always)]
-    #[track_caller]
-    pub fn lock(&self) -> LockGuard<'_, T> {
-        self.0.borrow_mut()
+    impl<'a, T: 'a> Drop for LockGuard<'a, T> {
+        #[inline]
+        fn drop(&mut self) {
+            // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
+            // with the `lock.mode` state. This means we access the right union fields.
+            match self.mode {
+                Mode::NoSync => {
+                    let cell = unsafe { &self.lock.mode_union.no_sync };
+                    debug_assert_eq!(cell.get(), true);
+                    cell.set(false);
+                }
+                // SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
+                Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
+            }
+        }
     }
-}
 
-/// A guard holding mutable access to a `Lock` which is in a locked state.
-#[cfg(parallel_compiler)]
-#[must_use = "if unused the Lock will immediately unlock"]
-pub struct LockGuard<'a, T> {
-    lock: &'a Lock<T>,
-    marker: PhantomData<&'a mut T>,
-}
+    union ModeUnion {
+        /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
+        no_sync: ManuallyDrop<Cell<bool>>,
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> Deref for LockGuard<'a, T> {
-    type Target = T;
-    #[inline]
-    fn deref(&self) -> &T {
-        // SAFETY: We have shared access to the mutable access owned by this type,
-        // so we can give out a shared reference.
-        unsafe { &*self.lock.data.get() }
+        /// A lock implementation that's only used if `Lock.mode` is `Sync`.
+        sync: ManuallyDrop<RawMutex>,
     }
-}
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut T {
-        // SAFETY: We have mutable access to the data so we can give out a mutable reference.
-        unsafe { &mut *self.lock.data.get() }
-    }
-}
+    /// The value representing a locked state for the `Cell`.
+    const LOCKED: bool = true;
 
-#[cfg(parallel_compiler)]
-impl<'a, T: 'a> Drop for LockGuard<'a, T> {
-    #[inline]
-    fn drop(&mut self) {
-        // SAFETY: We know that the lock is in a locked
-        // state because it is a invariant of this type.
-        unsafe { self.lock.raw.unlock() };
-    }
-}
+    /// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
+    /// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
+    pub struct Lock<T> {
+        /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
+        /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
+        /// This is set on initialization and never changed.
+        mode: Mode,
 
-#[cfg(parallel_compiler)]
-union LockRawUnion {
-    /// Indicates if the cell is locked. Only used if `LockRaw.sync` is false.
-    cell: ManuallyDrop<Cell<bool>>,
+        mode_union: ModeUnion,
+        data: UnsafeCell<T>,
+    }
 
-    /// A lock implementation that's only used if `LockRaw.sync` is true.
-    lock: ManuallyDrop<parking_lot::RawMutex>,
-}
+    impl<T> Lock<T> {
+        #[inline(always)]
+        pub fn new(inner: T) -> Self {
+            let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
+                // Create the lock with synchronization enabled using the `RawMutex` type.
+                (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
+            } else {
+                // Create the lock with synchronization disabled.
+                (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
+            };
+            Lock { mode, mode_union, data: UnsafeCell::new(inner) }
+        }
 
-/// A raw lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
-/// It contains no associated data and is used in the implementation of `Lock` which does have such data.
-///
-/// A manual implementation of a tagged union is used with the `sync` field and the `LockRawUnion` instead
-/// of using enums as it results in better code generation.
-#[cfg(parallel_compiler)]
-struct LockRaw {
-    /// Indicates if synchronization is used via `opt.lock` if true,
-    /// or if a non-thread safe cell is used via `opt.cell`. This is set on initialization and never changed.
-    sync: bool,
-    opt: LockRawUnion,
-}
+        #[inline(always)]
+        pub fn into_inner(self) -> T {
+            self.data.into_inner()
+        }
 
-#[cfg(parallel_compiler)]
-impl LockRaw {
-    fn new() -> Self {
-        if unlikely(super::mode::might_be_dyn_thread_safe()) {
-            // Create the lock with synchronization enabled using the `RawMutex` type.
-            LockRaw {
-                sync: true,
-                opt: LockRawUnion { lock: ManuallyDrop::new(parking_lot::RawMutex::INIT) },
-            }
-        } else {
-            // Create the lock with synchronization disabled.
-            LockRaw { sync: false, opt: LockRawUnion { cell: ManuallyDrop::new(Cell::new(false)) } }
+        #[inline(always)]
+        pub fn get_mut(&mut self) -> &mut T {
+            self.data.get_mut()
         }
-    }
 
-    #[inline(always)]
-    fn try_lock(&self) -> bool {
-        // SAFETY: This is safe since the union fields are used in accordance with `self.sync`.
-        unsafe {
-            if likely(!self.sync) {
-                if self.opt.cell.get() {
-                    false
-                } else {
-                    self.opt.cell.set(true);
-                    true
+        #[inline(always)]
+        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
+            let mode = self.mode;
+            // SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
+            match mode {
+                Mode::NoSync => {
+                    let cell = unsafe { &self.mode_union.no_sync };
+                    let was_unlocked = cell.get() != LOCKED;
+                    if was_unlocked {
+                        cell.set(LOCKED);
+                    }
+                    was_unlocked
                 }
-            } else {
-                self.opt.lock.try_lock()
+                Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
             }
+            .then(|| LockGuard { lock: self, marker: PhantomData, mode })
         }
-    }
 
-    #[inline(always)]
-    fn lock(&self) {
-        if super::ERROR_CHECKING {
-            // We're in the debugging mode, so assert that the lock is not held so we
-            // get a panic instead of waiting for the lock.
-            assert_eq!(self.try_lock(), true, "lock must not be hold");
-        } else {
-            // SAFETY: This is safe since the union fields are used in accordance with `self.sync`.
+        /// This acquires the lock assuming syncronization is in a specific mode.
+        ///
+        /// Safety
+        /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
+        /// true on lock creation.
+        #[inline(always)]
+        #[track_caller]
+        pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
+            #[inline(never)]
+            #[track_caller]
+            #[cold]
+            fn lock_held() -> ! {
+                panic!("lock was already held")
+            }
+
+            // SAFETY: This is safe since the union fields are used in accordance with `mode`
+            // which also must match `self.mode` due to the safety precondition.
             unsafe {
-                if likely(!self.sync) {
-                    if unlikely(self.opt.cell.replace(true)) {
-                        cold_path(|| panic!("lock was already held"))
+                match mode {
+                    Mode::NoSync => {
+                        if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
+                            lock_held()
+                        }
                     }
-                } else {
-                    self.opt.lock.lock();
+                    Mode::Sync => self.mode_union.sync.lock(),
                 }
             }
+            LockGuard { lock: self, marker: PhantomData, mode }
         }
-    }
 
-    /// This unlocks the lock.
-    ///
-    /// Safety
-    /// This method may only be called if the lock is currently held.
-    #[inline(always)]
-    unsafe fn unlock(&self) {
-        // SAFETY: The union use is safe since the union fields are used in accordance with
-        // `self.sync` and the `unlock` method precondition is upheld by the caller.
-        unsafe {
-            if likely(!self.sync) {
-                debug_assert_eq!(self.opt.cell.get(), true);
-                self.opt.cell.set(false);
-            } else {
-                self.opt.lock.unlock();
-            }
+        #[inline(always)]
+        #[track_caller]
+        pub fn lock(&self) -> LockGuard<'_, T> {
+            unsafe { self.lock_assume(self.mode) }
         }
     }
-}
 
-/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
-/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
-#[cfg(parallel_compiler)]
-pub struct Lock<T> {
-    raw: LockRaw,
-    data: UnsafeCell<T>,
+    #[cfg(parallel_compiler)]
+    unsafe impl<T: DynSend> DynSend for Lock<T> {}
+    #[cfg(parallel_compiler)]
+    unsafe impl<T: DynSend> DynSync for Lock<T> {}
 }
 
-#[cfg(parallel_compiler)]
-impl<T> Lock<T> {
-    #[inline(always)]
-    pub fn new(inner: T) -> Self {
-        Lock { raw: LockRaw::new(), data: UnsafeCell::new(inner) }
-    }
+mod no_sync {
+    use super::Mode;
+    use std::cell::RefCell;
 
-    #[inline(always)]
-    pub fn into_inner(self) -> T {
-        self.data.into_inner()
-    }
+    pub use std::cell::RefMut as LockGuard;
 
-    #[inline(always)]
-    pub fn get_mut(&mut self) -> &mut T {
-        self.data.get_mut()
-    }
+    pub struct Lock<T>(RefCell<T>);
 
-    #[inline(always)]
-    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-        if self.raw.try_lock() { Some(LockGuard { lock: self, marker: PhantomData }) } else { None }
-    }
+    impl<T> Lock<T> {
+        #[inline(always)]
+        pub fn new(inner: T) -> Self {
+            Lock(RefCell::new(inner))
+        }
 
-    #[inline(always)]
-    pub fn lock(&self) -> LockGuard<'_, T> {
-        self.raw.lock();
-        LockGuard { lock: self, marker: PhantomData }
+        #[inline(always)]
+        pub fn into_inner(self) -> T {
+            self.0.into_inner()
+        }
+
+        #[inline(always)]
+        pub fn get_mut(&mut self) -> &mut T {
+            self.0.get_mut()
+        }
+
+        #[inline(always)]
+        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
+            self.0.try_borrow_mut().ok()
+        }
+
+        #[inline(always)]
+        #[track_caller]
+        // This is unsafe to match the API for the `parallel_compiler` case.
+        pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> {
+            self.0.borrow_mut()
+        }
+
+        #[inline(always)]
+        #[track_caller]
+        pub fn lock(&self) -> LockGuard<'_, T> {
+            self.0.borrow_mut()
+        }
     }
 }
 
@@ -244,12 +249,13 @@ impl<T> Lock<T> {
     }
 }
 
-#[cfg(parallel_compiler)]
-unsafe impl<T: DynSend> DynSend for Lock<T> {}
-#[cfg(parallel_compiler)]
-unsafe impl<T: DynSend> DynSync for Lock<T> {}
+impl<T: Default> Default for Lock<T> {
+    #[inline]
+    fn default() -> Self {
+        Lock::new(T::default())
+    }
+}
 
-#[cfg(parallel_compiler)]
 impl<T: fmt::Debug> fmt::Debug for Lock<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.try_lock() {
@@ -267,10 +273,3 @@ impl<T: fmt::Debug> fmt::Debug for Lock<T> {
         }
     }
 }
-
-impl<T: Default> Default for Lock<T> {
-    #[inline]
-    fn default() -> Self {
-        Lock::new(T::default())
-    }
-}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 1a16759d7f9..f38adefa7c0 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -162,9 +162,10 @@ pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T
 pub trait Callbacks {
     /// Called before creating the compiler instance
     fn config(&mut self, _config: &mut interface::Config) {}
-    /// Called after parsing. Return value instructs the compiler whether to
+    /// Called after parsing the crate root. Submodules are not yet parsed when
+    /// this callback is called. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_parsing<'tcx>(
+    fn after_crate_root_parsing<'tcx>(
         &mut self,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
@@ -184,7 +185,6 @@ pub trait Callbacks {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
@@ -313,6 +313,7 @@ fn run_compiler(
         override_queries: None,
         make_codegen_backend,
         registry: diagnostics_registry(),
+        expanded_args: args,
     };
 
     match make_input(&early_error_handler, &matches.free) {
@@ -406,7 +407,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
+            if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -444,7 +445,7 @@ fn run_compiler(
 
             queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
 
-            if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
+            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0401.md b/compiler/rustc_error_codes/src/error_codes/E0401.md
index 4c93053d5f8..45d083681e5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0401.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0401.md
@@ -1,4 +1,4 @@
-Inner items do not inherit type or const parameters from the functions
+Inner items do not inherit the generic parameters from the items
 they are embedded in.
 
 Erroneous code example:
@@ -32,8 +32,8 @@ fn foo<T>(x: T) {
 }
 ```
 
-Items inside functions are basically just like top-level items, except
-that they can only be used from the function they are in.
+Items nested inside other items are basically just like top-level items, except
+that they can only be used from the item they are in.
 
 There are a couple of solutions for this.
 
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index d7a008f9a57..5d3b2f45166 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -169,7 +169,7 @@ impl AnnotateSnippetEmitterWriter {
                         .map(|line| {
                             // Ensure the source file is present before we try
                             // to load a string from it.
-                            source_map.ensure_source_file_source_present(file.clone());
+                            source_map.ensure_source_file_source_present(&file);
                             (
                                 format!("{}", source_map.filename_for_diagnostics(&file.name)),
                                 source_string(file.clone(), &line),
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index da108327ae7..58be74f887b 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1193,7 +1193,7 @@ impl EmitterWriter {
         let will_be_emitted = |span: Span| {
             !span.is_dummy() && {
                 let file = sm.lookup_source_file(span.hi());
-                sm.ensure_source_file_source_present(file)
+                sm.ensure_source_file_source_present(&file)
             }
         };
 
@@ -1388,7 +1388,7 @@ impl EmitterWriter {
         // Print out the annotate source lines that correspond with the error
         for annotated_file in annotated_files {
             // we can't annotate anything if the source is unavailable.
-            if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
+            if !sm.ensure_source_file_source_present(&annotated_file.file) {
                 if !self.short_message {
                     // We'll just print an unannotated message.
                     for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 390bf28df09..38667c5ff81 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -558,7 +558,7 @@ impl DiagnosticSpanLine {
             .span_to_lines(span)
             .map(|lines| {
                 // We can't get any lines if the source is unavailable.
-                if !je.sm.ensure_source_file_source_present(lines.file.clone()) {
+                if !je.sm.ensure_source_file_source_present(&lines.file) {
                     return vec![];
                 }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 55c4ec66cd9..990bd2d1cc9 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -44,7 +44,7 @@ use rustc_fluent_macro::fluent_messages;
 pub use rustc_lint_defs::{pluralize, Applicability};
 use rustc_span::source_map::SourceMap;
 pub use rustc_span::ErrorGuaranteed;
-use rustc_span::{Loc, Span};
+use rustc_span::{Loc, Span, DUMMY_SP};
 
 use std::borrow::Cow;
 use std::error::Report;
@@ -273,7 +273,7 @@ impl CodeSuggestion {
                 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
 
                 // We can't splice anything if the source is unavailable.
-                if !sm.ensure_source_file_source_present(lines.file.clone()) {
+                if !sm.ensure_source_file_source_present(&lines.file) {
                     return None;
                 }
 
@@ -1754,7 +1754,7 @@ impl DelayedDiagnostic {
             BacktraceStatus::Captured => {
                 let inner = &self.inner;
                 self.inner.subdiagnostic(DelayedAtWithNewline {
-                    span: inner.span.primary_span().unwrap(),
+                    span: inner.span.primary_span().unwrap_or(DUMMY_SP),
                     emitted_at: inner.emitted_at.clone(),
                     note: self.note,
                 });
@@ -1764,7 +1764,7 @@ impl DelayedDiagnostic {
             _ => {
                 let inner = &self.inner;
                 self.inner.subdiagnostic(DelayedAtWithoutNewline {
-                    span: inner.span.primary_span().unwrap(),
+                    span: inner.span.primary_span().unwrap_or(DUMMY_SP),
                     emitted_at: inner.emitted_at.clone(),
                     note: self.note,
                 });
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 34d16bf00cd..f87f4aba2b9 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -587,7 +587,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 .resolver
                 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
 
-            if self.cx.sess.opts.incremental_relative_spans() {
+            if self.cx.sess.opts.incremental.is_some() {
                 for (invoc, _) in invocations.iter_mut() {
                     let expn_id = invoc.expansion_data.id;
                     let parent_def = self.cx.resolver.invocation_parent(expn_id);
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 597cae6ff33..50da2278312 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -222,6 +222,12 @@ hir_analysis_return_type_notation_on_non_rpitit =
     .note = function returns `{$ty}`, which is not compatible with associated type return bounds
     .label = this function must be `async` or return `impl Trait`
 
+hir_analysis_rpitit_refined = impl trait in impl method signature does not match trait method signature
+    .suggestion = replace the return type so that it matches the trait
+    .label = return type from trait method defined here
+    .unmatched_bound_label = this bound is stronger than that defined on the trait
+    .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+
 hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 6082d446979..ed4dde419c4 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     {
         // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
         // valid span, so we point at the whole path segment instead.
-        let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
+        let is_dummy = assoc_name.span == DUMMY_SP;
+
         let mut err = struct_span_err!(
             self.tcx().sess,
-            span,
+            if is_dummy { span } else { assoc_name.span },
             E0220,
             "associated type `{}` not found for `{}`",
             assoc_name,
             ty_param_name
         );
 
+        if is_dummy {
+            err.span_label(span, format!("associated type `{assoc_name}` not found"));
+            return err.emit();
+        }
+
         let all_candidate_names: Vec<_> = all_candidates()
             .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
             .filter_map(|item| {
@@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             })
             .collect();
 
-        if let (Some(suggested_name), true) = (
-            find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
-            assoc_name.span != DUMMY_SP,
-        ) {
+        if let Some(suggested_name) =
+            find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
+        {
             err.span_suggestion(
                 assoc_name.span,
                 "there is an associated type with a similar name",
@@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             })
             .collect();
 
-        if let (Some(suggested_name), true) = (
-            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
-            assoc_name.span != DUMMY_SP,
-        ) {
+        if let Some(suggested_name) =
+            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
+        {
             if let [best_trait] = visible_traits
                 .iter()
                 .filter(|trait_def_id| {
@@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
-        err.span_label(span, format!("associated type `{assoc_name}` not found"));
+        // If we still couldn't find any associated type, and only one associated type exists,
+        // suggests using it.
+
+        if all_candidate_names.len() == 1 {
+            // this should still compile, except on `#![feature(associated_type_defaults)]`
+            // where it could suggests `type A = Self::A`, thus recursing infinitely
+            let applicability = if self.tcx().features().associated_type_defaults {
+                Applicability::Unspecified
+            } else {
+                Applicability::MaybeIncorrect
+            };
+
+            err.span_suggestion(
+                assoc_name.span,
+                format!("`{ty_param_name}` has the following associated type"),
+                all_candidate_names.first().unwrap().to_string(),
+                applicability,
+            );
+        } else {
+            err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
+        }
+
         err.emit()
     }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 90f64e18632..acfd8dcb112 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -523,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             Ty::new_misc_error(tcx).into()
                         }
                     }
-                    GenericParamDefKind::Const { has_default } => {
+                    GenericParamDefKind::Const { has_default, .. } => {
                         let ty = tcx
                             .at(self.span)
                             .type_of(param.def_id)
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index bd0ab6463f0..92cc9759304 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -28,6 +28,8 @@ use rustc_trait_selection::traits::{
 use std::borrow::Cow;
 use std::iter;
 
+mod refine;
+
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
 ///
@@ -53,6 +55,12 @@ pub(super) fn compare_impl_method<'tcx>(
             impl_trait_ref,
             CheckImpliedWfMode::Check,
         )?;
+        refine::check_refining_return_position_impl_trait_in_trait(
+            tcx,
+            impl_m,
+            trait_m,
+            impl_trait_ref,
+        );
     };
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
new file mode 100644
index 00000000000..a8149b634ef
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -0,0 +1,311 @@
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
+use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT;
+use rustc_middle::traits::{ObligationCause, Reveal};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+};
+use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::traits::{
+    elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt,
+};
+use std::ops::ControlFlow;
+
+/// Check that an implementation does not refine an RPITIT from a trait method signature.
+pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: ty::AssocItem,
+    trait_m: ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) {
+    if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) {
+        return;
+    }
+    // crate-private traits don't have any library guarantees, there's no need to do this check.
+    if !tcx.visibility(trait_m.container_id(tcx)).is_public() {
+        return;
+    }
+
+    // If a type in the trait ref is private, then there's also no reason to to do this check.
+    let impl_def_id = impl_m.container_id(tcx);
+    for arg in impl_trait_ref.args {
+        if let Some(ty) = arg.as_type()
+            && let Some(self_visibility) = type_visibility(tcx, ty)
+            && !self_visibility.is_public()
+        {
+            return;
+        }
+    }
+
+    let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id);
+    let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args);
+    let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args);
+    let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig);
+    // replace the self type of the trait ref with `Self` so that diagnostics render better.
+    let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions(
+        impl_m.def_id,
+        tcx.fn_sig(trait_m.def_id).instantiate(
+            tcx,
+            tcx.mk_args_from_iter(
+                [tcx.types.self_param.into()]
+                    .into_iter()
+                    .chain(trait_m_to_impl_m_args.iter().skip(1)),
+            ),
+        ),
+    );
+
+    let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else {
+        // Error already emitted, no need to delay another.
+        return;
+    };
+
+    let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() };
+    trait_m_sig.visit_with(&mut collector);
+
+    // Bound that we find on RPITITs in the trait signature.
+    let mut trait_bounds = vec![];
+    // Bounds that we find on the RPITITs in the impl signature.
+    let mut impl_bounds = vec![];
+
+    for trait_projection in collector.types.into_iter().rev() {
+        let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
+        let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args);
+
+        // If the hidden type is not an opaque, then we have "refined" the trait signature.
+        let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else {
+            report_mismatched_rpitit_signature(
+                tcx,
+                trait_m_sig_with_self_for_diag,
+                trait_m.def_id,
+                impl_m.def_id,
+                None,
+            );
+            return;
+        };
+
+        // This opaque also needs to be from the impl method -- otherwise,
+        // it's a refinement to a TAIT.
+        if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| {
+            matches!(
+                node.expect_item().expect_opaque_ty().origin,
+                hir::OpaqueTyOrigin::AsyncFn(def_id)  | hir::OpaqueTyOrigin::FnReturn(def_id)
+                    if def_id == impl_m.def_id.expect_local()
+            )
+        }) {
+            report_mismatched_rpitit_signature(
+                tcx,
+                trait_m_sig_with_self_for_diag,
+                trait_m.def_id,
+                impl_m.def_id,
+                None,
+            );
+            return;
+        }
+
+        trait_bounds.extend(
+            tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args),
+        );
+        impl_bounds.extend(elaborate(
+            tcx,
+            tcx.explicit_item_bounds(impl_opaque.def_id)
+                .iter_instantiated_copied(tcx, impl_opaque.args),
+        ));
+    }
+
+    let hybrid_preds = tcx
+        .predicates_of(impl_def_id)
+        .instantiate_identity(tcx)
+        .into_iter()
+        .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args))
+        .map(|(clause, _)| clause);
+    let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
+    let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy());
+
+    let ref infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+
+    // Normalize the bounds. This has two purposes:
+    //
+    // 1. Project the RPITIT projections from the trait to the opaques on the impl,
+    //    which means that they don't need to be mapped manually.
+    //
+    // 2. Project any other projections that show up in the bound. That makes sure that
+    //    we don't consider `tests/ui/async-await/in-trait/async-associated-types.rs`
+    //    to be refining.
+    let (trait_bounds, impl_bounds) =
+        ocx.normalize(&ObligationCause::dummy(), param_env, (trait_bounds, impl_bounds));
+
+    // Since we've normalized things, we need to resolve regions, since we'll
+    // possibly have introduced region vars during projection. We don't expect
+    // this resolution to have incurred any region errors -- but if we do, then
+    // just delay a bug.
+    let mut implied_wf_types = FxIndexSet::default();
+    implied_wf_types.extend(trait_m_sig.inputs_and_output);
+    implied_wf_types.extend(ocx.normalize(
+        &ObligationCause::dummy(),
+        param_env,
+        trait_m_sig.inputs_and_output,
+    ));
+    if !ocx.select_all_or_error().is_empty() {
+        tcx.sess.delay_span_bug(
+            DUMMY_SP,
+            "encountered errors when checking RPITIT refinement (selection)",
+        );
+        return;
+    }
+    let outlives_env = OutlivesEnvironment::with_bounds(
+        param_env,
+        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
+    );
+    let errors = infcx.resolve_regions(&outlives_env);
+    if !errors.is_empty() {
+        tcx.sess.delay_span_bug(
+            DUMMY_SP,
+            "encountered errors when checking RPITIT refinement (regions)",
+        );
+        return;
+    }
+    // Resolve any lifetime variables that may have been introduced during normalization.
+    let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else {
+        tcx.sess.delay_span_bug(
+            DUMMY_SP,
+            "encountered errors when checking RPITIT refinement (resolution)",
+        );
+        return;
+    };
+
+    // For quicker lookup, use an `IndexSet`
+    // (we don't use one earlier because it's not foldable..)
+    let trait_bounds = FxIndexSet::from_iter(trait_bounds);
+
+    // Find any clauses that are present in the impl's RPITITs that are not
+    // present in the trait's RPITITs. This will trigger on trivial predicates,
+    // too, since we *do not* use the trait solver to prove that the RPITIT's
+    // bounds are not stronger -- we're doing a simple, syntactic compatibility
+    // check between bounds. This is strictly forwards compatible, though.
+    for (clause, span) in impl_bounds {
+        if !trait_bounds.contains(&clause) {
+            report_mismatched_rpitit_signature(
+                tcx,
+                trait_m_sig_with_self_for_diag,
+                trait_m.def_id,
+                impl_m.def_id,
+                Some(span),
+            );
+            return;
+        }
+    }
+}
+
+struct ImplTraitInTraitCollector<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    types: FxIndexSet<ty::AliasTy<'tcx>>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'tcx> {
+    type BreakTy = !;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+        if let ty::Alias(ty::Projection, proj) = *ty.kind()
+            && self.tcx.is_impl_trait_in_trait(proj.def_id)
+        {
+            if self.types.insert(proj) {
+                for (pred, _) in self
+                    .tcx
+                    .explicit_item_bounds(proj.def_id)
+                    .iter_instantiated_copied(self.tcx, proj.args)
+                {
+                    pred.visit_with(self)?;
+                }
+            }
+            ControlFlow::Continue(())
+        } else {
+            ty.super_visit_with(self)
+        }
+    }
+}
+
+fn report_mismatched_rpitit_signature<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_m_sig: ty::FnSig<'tcx>,
+    trait_m_def_id: DefId,
+    impl_m_def_id: DefId,
+    unmatched_bound: Option<Span>,
+) {
+    let mapping = std::iter::zip(
+        tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(),
+        tcx.fn_sig(impl_m_def_id).skip_binder().bound_vars(),
+    )
+    .filter_map(|(impl_bv, trait_bv)| {
+        if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+            && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+        {
+            Some((impl_bv, trait_bv))
+        } else {
+            None
+        }
+    })
+    .collect();
+
+    let mut return_ty =
+        trait_m_sig.output().fold_with(&mut super::RemapLateBound { tcx, mapping: &mapping });
+
+    if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() {
+        let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else {
+            bug!();
+        };
+        let Some(future_output_ty) = tcx
+            .explicit_item_bounds(future_ty.def_id)
+            .iter_instantiated_copied(tcx, future_ty.args)
+            .find_map(|(clause, _)| match clause.kind().no_bound_vars()? {
+                ty::ClauseKind::Projection(proj) => proj.term.ty(),
+                _ => None,
+            })
+        else {
+            bug!()
+        };
+        return_ty = future_output_ty;
+    }
+
+    let (span, impl_return_span, pre, post) =
+        match tcx.hir().get_by_def_id(impl_m_def_id.expect_local()).fn_decl().unwrap().output {
+            hir::FnRetTy::DefaultReturn(span) => (tcx.def_span(impl_m_def_id), span, "-> ", " "),
+            hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""),
+        };
+    let trait_return_span =
+        tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output {
+            hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id),
+            hir::FnRetTy::Return(ty) => ty.span,
+        });
+
+    let span = unmatched_bound.unwrap_or(span);
+    tcx.emit_spanned_lint(
+        REFINING_IMPL_TRAIT,
+        tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()),
+        span,
+        crate::errors::ReturnPositionImplTraitInTraitRefined {
+            impl_return_span,
+            trait_return_span,
+            pre,
+            post,
+            return_ty,
+            unmatched_bound,
+        },
+    );
+}
+
+fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<ty::Visibility<DefId>> {
+    match *ty.kind() {
+        ty::Ref(_, ty, _) => type_visibility(tcx, ty),
+        ty::Adt(def, args) => {
+            if def.is_fundamental() {
+                type_visibility(tcx, args.type_at(0))
+            } else {
+                Some(tcx.visibility(def.did()))
+            }
+        }
+        _ => None,
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f5beefc47f3..b97e0a80fe6 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1255,7 +1255,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
         GenericParamDefKind::Type { has_default, .. }
-        | GenericParamDefKind::Const { has_default } => {
+        | GenericParamDefKind::Const { has_default, .. } => {
             has_default && def.index >= generics.parent_count as u32
         }
         GenericParamDefKind::Lifetime => unreachable!(),
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 67aef0a7c43..94f3e8706fc 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -157,6 +157,14 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     let infcx = tcx.infer_ctxt().build();
     let cause = ObligationCause::misc(span, impl_did);
 
+    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
+    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
+    // that are effectively repr(transparent) newtypes around types that already hav a
+    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some
+    // of them support an allocator, but we ensure that for the cases where the type implements this
+    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
+    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
+    // even if they do not carry that attribute.
     use rustc_type_ir::sty::TyKind::*;
     match (source.kind(), target.kind()) {
         (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 4842008279a..3d60c57b9d5 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -328,7 +328,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 name: param.name.ident().name,
                 def_id: param.def_id.to_def_id(),
                 pure_wrt_drop: param.pure_wrt_drop,
-                kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+                kind: ty::GenericParamDefKind::Const {
+                    has_default: default.is_some(),
+                    is_host_effect: is_host_param,
+                },
             })
         }
     }));
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 9471ad9ca90..7614913f4bf 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -919,6 +919,22 @@ pub struct UnusedAssociatedTypeBounds {
     pub span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_analysis_rpitit_refined)]
+#[note]
+pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
+    #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")]
+    pub impl_return_span: Span,
+    #[label]
+    pub trait_return_span: Option<Span>,
+    #[label(hir_analysis_unmatched_bound_label)]
+    pub unmatched_bound: Option<Span>,
+
+    pub pre: &'static str,
+    pub post: &'static str,
+    pub return_ty: Ty<'tcx>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_assoc_bound_on_const)]
 #[note]
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 4f95174f869..b0f333b79ca 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -237,6 +237,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
+    // Freeze definitions as we don't add new ones at this point. This improves performance by
+    // allowing lock-free access to them.
+    tcx.untracked().definitions.freeze();
+
     // FIXME: Remove this when we implement creating `DefId`s
     // for anon constants during their parents' typeck.
     // Typeck all body owners in parallel will produce queries
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 5b5986a349f..97091c39c65 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::{
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::{self, Ty};
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
@@ -23,20 +24,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
             self.fulfillment_cx.borrow_mut().pending_obligations()
         );
 
-        // Check if we have any unsolved variables. If not, no need for fallback.
-        let unsolved_variables = self.unsolved_variables();
-        if unsolved_variables.is_empty() {
-            return;
-        }
+        let fallback_occured = self.fallback_types() || self.fallback_effects();
 
-        let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
-
-        // We do fallback in two passes, to try to generate
-        // better error messages.
-        // The first time, we do *not* replace opaque types.
-        for ty in unsolved_variables {
-            debug!("unsolved_variable = {:?}", ty);
-            self.fallback_if_possible(ty, &diverging_fallback);
+        if !fallback_occured {
+            return;
         }
 
         // We now see if we can make progress. This might cause us to
@@ -65,6 +56,53 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         self.select_obligations_where_possible(|_| {});
     }
 
+    fn fallback_types(&self) -> bool {
+        // Check if we have any unsolved variables. If not, no need for fallback.
+        let unsolved_variables = self.unsolved_variables();
+
+        if unsolved_variables.is_empty() {
+            return false;
+        }
+
+        let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
+        for ty in unsolved_variables {
+            debug!("unsolved_variable = {:?}", ty);
+            self.fallback_if_possible(ty, &diverging_fallback);
+        }
+
+        true
+    }
+
+    fn fallback_effects(&self) -> bool {
+        let unsolved_effects = self.unsolved_effects();
+
+        if unsolved_effects.is_empty() {
+            return false;
+        }
+
+        // not setting `fallback_has_occured` here because that field is only used for type fallback
+        // diagnostics.
+
+        for effect in unsolved_effects {
+            let expected = self.tcx.consts.true_;
+            let cause = self.misc(rustc_span::DUMMY_SP);
+            match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) {
+                Ok(InferOk { obligations, value: () }) => {
+                    self.register_predicates(obligations);
+                }
+                Err(e) => {
+                    bug!("cannot eq unsolved effect: {e:?}")
+                }
+            }
+        }
+
+        true
+    }
+
     // Tries to apply a fallback to `ty` if it is an unsolved variable.
     //
     // - Unconstrained ints are replaced with `i32`.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 28fe2e062e5..c94cfde0670 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1295,17 +1295,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
                         self.fcx.ty_infer(Some(param), inf.span).into()
                     }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                    (
+                        &GenericParamDefKind::Const { has_default, is_host_effect },
+                        GenericArg::Infer(inf),
+                    ) => {
                         let tcx = self.fcx.tcx();
-                        self.fcx
-                            .ct_infer(
-                                tcx.type_of(param.def_id)
-                                    .no_bound_vars()
-                                    .expect("const parameter types cannot be generic"),
-                                Some(param),
-                                inf.span,
-                            )
-                            .into()
+
+                        if has_default && is_host_effect {
+                            self.fcx.var_for_effect(param)
+                        } else {
+                            self.fcx
+                                .ct_infer(
+                                    tcx.type_of(param.def_id)
+                                        .no_bound_vars()
+                                        .expect("const parameter types cannot be generic"),
+                                    Some(param),
+                                    inf.span,
+                                )
+                                .into()
+                        }
                     }
                     _ => unreachable!(),
                 }
@@ -1324,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
-                            // If we have a default, then we it doesn't matter that we're not
+                            // If we have a default, then it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.
                             tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
@@ -1336,17 +1344,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.fcx.var_for_def(self.span, param)
                         }
                     }
-                    GenericParamDefKind::Const { has_default } => {
-                        if !infer_args
-                            && has_default
-                            && !tcx.has_attr(param.def_id, sym::rustc_host)
-                        {
-                            tcx.const_param_default(param.def_id)
-                                .instantiate(tcx, args.unwrap())
-                                .into()
-                        } else {
-                            self.fcx.var_for_def(self.span, param)
+                    GenericParamDefKind::Const { has_default, is_host_effect } => {
+                        if has_default {
+                            // N.B. this is a bit of a hack. `infer_args` is passed depending on
+                            // whether the user has provided generic args. E.g. for `Vec::new`
+                            // we would have to infer the generic types. However, for `Vec::<T>::new`
+                            // where the allocator param `A` has a default we will *not* infer. But
+                            // for effect params this is a different story: if the user has not written
+                            // anything explicit for the effect param, we always need to try to infer
+                            // it before falling back to default, such that a `const fn` such as
+                            // `needs_drop::<()>` can still be called in const contexts. (if we defaulted
+                            // instead of inferred, typeck would error)
+                            if is_host_effect {
+                                return self.fcx.var_for_effect(param);
+                            } else if !infer_args {
+                                return tcx
+                                    .const_param_default(param.def_id)
+                                    .instantiate(tcx, args.unwrap())
+                                    .into();
+                            }
                         }
+
+                        self.fcx.var_for_def(self.span, param)
                     }
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 7707cc6de54..4237b4488ca 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -266,7 +266,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         param: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> Const<'tcx> {
+        // FIXME ideally this shouldn't use unwrap
         match param {
+            Some(
+                param @ ty::GenericParamDef {
+                    kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
+                    ..
+                },
+            ) => self.var_for_effect(param).as_const().unwrap(),
             Some(param) => self.var_for_def(span, param).as_const().unwrap(),
             None => self.next_const_var(
                 ty,
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 6a817122491..566dc09cdd2 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -643,17 +643,14 @@ fn check_must_not_suspend_ty<'tcx>(
         }
         ty::Array(ty, len) => {
             let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
+            let target_usize =
+                len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize;
+            let plural_len = target_usize.saturating_add(1);
             check_must_not_suspend_ty(
                 fcx,
                 ty,
                 hir_id,
-                SuspendCheckData {
-                    descr_pre,
-                    plural_len: len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0)
-                        as usize
-                        + 1,
-                    ..data
-                },
+                SuspendCheckData { descr_pre, plural_len, ..data },
             )
         }
         // If drop tracking is enabled, we want to look through references, since the referent
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 0cfaf583774..7719482890e 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -48,18 +48,6 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
 
         join(
             move || {
-                sess.time("incr_comp_persist_result_cache", || {
-                    // Drop the memory map so that we can remove the file and write to it.
-                    if let Some(odc) = &tcx.query_system.on_disk_cache {
-                        odc.drop_serialized_data(tcx);
-                    }
-
-                    file_format::save_in(sess, query_cache_path, "query cache", |e| {
-                        encode_query_cache(tcx, e)
-                    });
-                });
-            },
-            move || {
                 sess.time("incr_comp_persist_dep_graph", || {
                     if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
                         sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
@@ -73,6 +61,20 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
                     }
                 });
             },
+            move || {
+                // We execute this after `incr_comp_persist_dep_graph` for the serial compiler
+                // to catch any potential query execution writing to the dep graph.
+                sess.time("incr_comp_persist_result_cache", || {
+                    // Drop the memory map so that we can remove the file and write to it.
+                    if let Some(odc) = &tcx.query_system.on_disk_cache {
+                        odc.drop_serialized_data(tcx);
+                    }
+
+                    file_format::save_in(sess, query_cache_path, "query cache", |e| {
+                        encode_query_cache(tcx, e)
+                    });
+                });
+            },
         );
     })
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9d7a9fefd08..99bd296d0d5 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -522,6 +522,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                     }
                 }
             }
+            ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
+                match self.infcx.probe_effect_var(vid) {
+                    Some(value) => return self.fold_const(value.as_const(self.infcx.tcx)),
+                    None => {
+                        return self.canonicalize_const_var(
+                            CanonicalVarInfo { kind: CanonicalVarKind::Effect },
+                            ct,
+                        );
+                    }
+                }
+            }
             ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                 bug!("encountered a fresh const during canonicalization")
             }
@@ -690,7 +701,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             .iter()
             .map(|v| CanonicalVarInfo {
                 kind: match v.kind {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
+                    | CanonicalVarKind::Effect => {
                         return *v;
                     }
                     CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 8ca2e403043..41787ee2942 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -151,7 +151,11 @@ impl<'tcx> InferCtxt<'tcx> {
                     universe_map(ui),
                 )
                 .into(),
-
+            CanonicalVarKind::Effect => {
+                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
+                    .into()
+            }
             CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index ddc8e7e50eb..ee13eb0271e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -30,7 +30,7 @@ use super::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::infer::generalize::{self, CombineDelegate, Generalization};
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::infer::canonical::OriginalQueryValues;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
@@ -91,7 +91,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .borrow_mut()
                     .float_unification_table()
                     .unify_var_var(a_id, b_id)
-                    .map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
+                    .map_err(|e| float_unification_error(a_is_expected, e))?;
                 Ok(a)
             }
             (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
@@ -210,10 +210,30 @@ impl<'tcx> InferCtxt<'tcx> {
                 return Ok(a);
             }
 
+            (
+                ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
+                ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
+            ) => {
+                self.inner
+                    .borrow_mut()
+                    .effect_unification_table()
+                    .unify_var_var(a_vid, b_vid)
+                    .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?;
+                return Ok(a);
+            }
+
             // All other cases of inference with other variables are errors.
-            (ty::ConstKind::Infer(InferConst::Var(_)), ty::ConstKind::Infer(_))
-            | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(InferConst::Var(_))) => {
-                bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)")
+            (
+                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
+                ty::ConstKind::Infer(_),
+            )
+            | (
+                ty::ConstKind::Infer(_),
+                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
+            ) => {
+                bug!(
+                    "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
+                )
             }
 
             (ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
@@ -223,6 +243,23 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
                 return self.unify_const_variable(vid, a, relation.param_env());
             }
+
+            (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
+                return self.unify_effect_variable(
+                    relation.a_is_expected(),
+                    vid,
+                    EffectVarValue::Const(b),
+                );
+            }
+
+            (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
+                return self.unify_effect_variable(
+                    !relation.a_is_expected(),
+                    vid,
+                    EffectVarValue::Const(a),
+                );
+            }
+
             (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
                 if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
             {
@@ -340,6 +377,20 @@ impl<'tcx> InferCtxt<'tcx> {
             .map_err(|e| float_unification_error(vid_is_expected, e))?;
         Ok(Ty::new_float(self.tcx, val))
     }
+
+    fn unify_effect_variable(
+        &self,
+        vid_is_expected: bool,
+        vid: ty::EffectVid<'tcx>,
+        val: EffectVarValue<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        self.inner
+            .borrow_mut()
+            .effect_unification_table()
+            .unify_var_value(vid, Some(val))
+            .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?;
+        Ok(val.as_const(self.tcx))
+    }
 }
 
 impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
@@ -493,3 +544,11 @@ fn float_unification_error<'tcx>(
     let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
     TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
 }
+
+fn effect_unification_error<'tcx>(
+    _tcx: TyCtxt<'tcx>,
+    _a_is_expected: bool,
+    (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>),
+) -> TypeError<'tcx> {
+    bug!("unexpected effect unification error")
+}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 689945d644c..0596ce373cf 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -156,6 +156,21 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
                     .known();
                 self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
+                let opt_ct = self
+                    .infcx
+                    .inner
+                    .borrow_mut()
+                    .effect_unification_table()
+                    .probe_value(v)
+                    .map(|effect| effect.as_const(self.infcx.tcx));
+                self.freshen_const(
+                    opt_ct,
+                    ty::InferConst::EffectVar(v),
+                    ty::InferConst::Fresh,
+                    ct.ty(),
+                )
+            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
                 if i >= self.const_freshen_count {
                     bug!(
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index cf674d5dda6..dd7f8d35441 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -403,6 +403,7 @@ where
                     }
                 }
             }
+            ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
             // FIXME: remove this branch once `structurally_relate_consts` is fully
             // structural.
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index aaabf1482e2..abb59a789da 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -21,7 +21,7 @@ use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
@@ -33,13 +33,14 @@ use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
-use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
+use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
+use std::marker::PhantomData;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -115,6 +116,9 @@ pub struct InferCtxtInner<'tcx> {
     /// Map from floating variable to the kind of float it represents.
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
+    /// Map from effect variable to the effect param it represents.
+    effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
+
     /// Tracks the set of region variables and the constraints between them.
     ///
     /// This is initially `Some(_)` but when
@@ -172,6 +176,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
             const_unification_storage: ut::UnificationTableStorage::new(),
             int_unification_storage: ut::UnificationTableStorage::new(),
             float_unification_storage: ut::UnificationTableStorage::new(),
+            effect_unification_storage: ut::UnificationTableStorage::new(),
             region_constraint_storage: Some(RegionConstraintStorage::new()),
             region_obligations: vec![],
             opaque_type_storage: Default::default(),
@@ -223,6 +228,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
         self.const_unification_storage.with_log(&mut self.undo_log)
     }
 
+    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
+        self.effect_unification_storage.with_log(&mut self.undo_log)
+    }
+
     #[inline]
     pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
         self.region_constraint_storage
@@ -356,6 +365,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
                 Err(universe) => Some(universe),
                 Ok(_) => None,
             },
+            EffectVar(_) => None,
             Fresh(_) => None,
         }
     }
@@ -764,19 +774,32 @@ impl<'tcx> InferCtxt<'tcx> {
             .collect();
         vars.extend(
             (0..inner.int_unification_table().len())
-                .map(|i| ty::IntVid { index: i as u32 })
+                .map(|i| ty::IntVid::from_u32(i as u32))
                 .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none())
                 .map(|v| Ty::new_int_var(self.tcx, v)),
         );
         vars.extend(
             (0..inner.float_unification_table().len())
-                .map(|i| ty::FloatVid { index: i as u32 })
+                .map(|i| ty::FloatVid::from_u32(i as u32))
                 .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none())
                 .map(|v| Ty::new_float_var(self.tcx, v)),
         );
         vars
     }
 
+    pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> {
+        let mut inner = self.inner.borrow_mut();
+        let mut table = inner.effect_unification_table();
+
+        (0..table.len())
+            .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
+            .filter(|&vid| table.probe_value(vid).is_none())
+            .map(|v| {
+                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
+            })
+            .collect()
+    }
+
     fn combine_fields<'a>(
         &'a self,
         trace: TypeTrace<'tcx>,
@@ -1158,7 +1181,10 @@ impl<'tcx> InferCtxt<'tcx> {
 
                 Ty::new_var(self.tcx, ty_var_id).into()
             }
-            GenericParamDefKind::Const { .. } => {
+            GenericParamDefKind::Const { is_host_effect, .. } => {
+                if is_host_effect {
+                    return self.var_for_effect(param);
+                }
                 let origin = ConstVariableOrigin {
                     kind: ConstVariableOriginKind::ConstParameterDefinition(
                         param.name,
@@ -1184,6 +1210,17 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 
+    pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
+        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+        let ty = self
+            .tcx
+            .type_of(param.def_id)
+            .no_bound_vars()
+            .expect("const parameter types cannot be generic");
+        debug_assert_eq!(self.tcx.types.bool, ty);
+        ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
+    }
+
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
     pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
@@ -1369,6 +1406,10 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 
+    pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
+        self.inner.borrow_mut().effect_unification_table().probe_value(vid)
+    }
+
     /// Attempts to resolve all type/region/const variables in
     /// `value`. Region inference must have been run already (e.g.,
     /// by calling `resolve_regions_and_report_errors`). If some
@@ -1649,6 +1690,14 @@ impl<'tcx> InferCtxt<'tcx> {
                     ConstVariableValue::Known { .. } => true,
                 }
             }
+
+            TyOrConstInferVar::Effect(v) => {
+                // If `probe_value` returns `Some`, it never equals
+                // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`.
+                //
+                // Not `inlined_probe_value(v)` because this call site is colder.
+                self.probe_effect_var(v).is_some()
+            }
         }
     }
 }
@@ -1720,6 +1769,8 @@ pub enum TyOrConstInferVar<'tcx> {
 
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
     Const(ConstVid<'tcx>),
+    /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
+    Effect(EffectVid<'tcx>),
 }
 
 impl<'tcx> TyOrConstInferVar<'tcx> {
@@ -1750,6 +1801,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
     fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
         match ct.kind() {
             ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
+            ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
             _ => None,
         }
     }
@@ -1793,17 +1845,24 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
-            self.infcx
+        match ct.kind() {
+            ty::ConstKind::Infer(InferConst::Var(vid)) => self
+                .infcx
                 .inner
                 .borrow_mut()
                 .const_unification_table()
                 .probe_value(vid)
                 .val
                 .known()
-                .unwrap_or(ct)
-        } else {
-            ct
+                .unwrap_or(ct),
+            ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .effect_unification_table()
+                .probe_value(vid)
+                .map_or(ct, |val| val.as_const(self.infcx.tcx)),
+            _ => ct,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 1c3a5c36076..09df93fcc2f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -145,7 +145,25 @@ impl<'tcx> InferCtxt<'tcx> {
                             return None;
                         }
                     }
-                    DefiningAnchor::Bubble => {}
+                    DefiningAnchor::Bubble => {
+                        if let ty::Alias(ty::Opaque, _) = b.kind() {
+                            // In bubble mode we don't know which of the two opaque types is supposed to have the other
+                            // as a hidden type (both, none or either one of them could be in its defining scope).
+                            let predicate = ty::PredicateKind::AliasRelate(
+                                a.into(),
+                                b.into(),
+                                ty::AliasRelationDirection::Equate,
+                            );
+                            let obligation = traits::Obligation::new(
+                                self.tcx,
+                                cause.clone(),
+                                param_env,
+                                predicate,
+                            );
+                            let obligations = vec![obligation];
+                            return Some(Ok(InferOk { value: (), obligations }));
+                        }
+                    }
                     DefiningAnchor::Error => return None,
                 };
                 if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 25d06b21ec8..79144b3e643 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -24,6 +24,7 @@ pub(crate) enum UndoLog<'tcx> {
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -55,6 +56,7 @@ impl_from! {
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
 
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
 
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
 
@@ -71,6 +73,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
             UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
             UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
             UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
+            UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo),
             UndoLog::RegionConstraintCollector(undo) => {
                 self.region_constraint_storage.as_mut().unwrap().reverse(undo)
             }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 5b417e008cf..a0f0b530bae 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -279,6 +279,12 @@ pub struct Config {
 
     /// Registry of diagnostics codes.
     pub registry: Registry,
+
+    /// All commandline args used to invoke the compiler, with @file args fully expanded.
+    /// This will only be used within debug info, e.g. in the pdb file on windows
+    /// This is mainly useful for other tools that reads that debuginfo to figure out
+    /// how to call the compiler with the same arguments.
+    pub expanded_args: Vec<String>,
 }
 
 // JUSTIFICATION: before session exists, only config
@@ -317,6 +323,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.make_codegen_backend,
                 registry.clone(),
                 config.ice_file,
+                config.expanded_args,
             );
 
             if let Some(parse_sess_created) = config.parse_sess_created {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 9fcaf643179..e5ae6d5b5d6 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -584,7 +584,7 @@ fn resolver_for_lowering<'tcx>(
     let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
 
     // Make sure we don't mutate the cstore from here on.
-    tcx.untracked().cstore.leak();
+    tcx.untracked().cstore.freeze();
 
     let ty::ResolverOutputs {
         global_ctxt: untracked_resolutions,
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 2db7aa0e367..449d7a29590 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceLock, RwLock, WorkerLocal};
+use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal};
 use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_incremental::DepGraphFuture;
@@ -114,6 +114,7 @@ impl<'tcx> Queries<'tcx> {
             .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
     }
 
+    #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."]
     pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
         self.pre_configure.compute(|| {
             let mut krate = self.parse()?.steal();
@@ -171,6 +172,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
         self.gcx.compute(|| {
             let sess = self.session();
+            #[allow(deprecated)]
             let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
 
             // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
@@ -193,11 +195,11 @@ impl<'tcx> Queries<'tcx> {
                 self.compiler.register_lints.as_deref(),
                 &pre_configured_attrs,
             ));
-            let cstore = RwLock::new(Box::new(CStore::new(
+            let cstore = FreezeLock::new(Box::new(CStore::new(
                 self.codegen_backend().metadata_loader(),
                 stable_crate_id,
             )) as _);
-            let definitions = RwLock::new(Definitions::new(stable_crate_id));
+            let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
             let source_span = AppendOnlyIndexVec::new();
             let _id = source_span.push(krate.spans.inner_span);
             debug_assert_eq!(_id, CRATE_DEF_ID);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index b53ba251bcd..ccf8b5630d4 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -68,6 +68,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
         None,
         "",
         None,
+        Default::default(),
     );
     (sess, cfg)
 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 5c9b39cdbe3..37e242c6e40 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -71,6 +71,7 @@ pub fn create_session(
     >,
     descriptions: Registry,
     ice_file: Option<PathBuf>,
+    expanded_args: Vec<String>,
 ) -> (Session, Box<dyn CodegenBackend>) {
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
@@ -113,6 +114,7 @@ pub fn create_session(
         target_override,
         rustc_version_str().unwrap_or("unknown"),
         ice_file,
+        expanded_args,
     );
 
     codegen_backend.init(&sess);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7f7f36ca170..ba50c9e00e3 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -156,15 +156,6 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
-lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
-
-lint_check_name_removed = lint `{$lint_name}` has been removed: {$reason}
-
-lint_check_name_renamed = lint `{$lint_name}` has been renamed to `{$replace}`
-
-lint_check_name_unknown = unknown lint: `{$lint_name}`
-    .help = did you mean: `{$suggestion}`
-
 lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
 
 lint_command_line_source = `forbid` lint level was set on command line
@@ -187,6 +178,7 @@ lint_default_source = `forbid` lint level is the default for {$id}
 lint_deprecated_lint_name =
     lint name `{$name}` is deprecated and may not have an effect in the future.
     .suggestion = change it to
+    .help = change it to {$replace}
 
 lint_diag_out_of_impl =
     diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
@@ -528,6 +520,7 @@ lint_unknown_gated_lint =
 lint_unknown_lint =
     unknown lint: `{$name}`
     .suggestion = did you mean
+    .help = did you mean: `{$replace}`
 
 lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
     .help = add `#![register_tool({$tool_name})]` to the crate root
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 9dfde84b552..7a336a8f694 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,10 +16,6 @@
 
 use self::TargetLint::*;
 
-use crate::errors::{
-    CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown,
-    CheckNameUnknownTool, RequestedLevel, UnsupportedGroup,
-};
 use crate::levels::LintLevelsBuilder;
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
@@ -330,58 +326,6 @@ impl LintStore {
         }
     }
 
-    /// Checks the validity of lint names derived from the command line.
-    pub fn check_lint_name_cmdline(
-        &self,
-        sess: &Session,
-        lint_name: &str,
-        level: Level,
-        registered_tools: &RegisteredTools,
-    ) {
-        let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
-        if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) {
-            sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
-            return;
-        }
-        match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
-            CheckLintNameResult::Renamed(replace) => {
-                sess.emit_warning(CheckNameRenamed {
-                    lint_name,
-                    replace: &replace,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::Removed(reason) => {
-                sess.emit_warning(CheckNameRemoved {
-                    lint_name,
-                    reason: &reason,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::NoLint(suggestion) => {
-                sess.emit_err(CheckNameUnknown {
-                    lint_name,
-                    suggestion,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::Tool(Err((Some(_), new_name))) => {
-                sess.emit_warning(CheckNameDeprecated {
-                    lint_name,
-                    new_name: &new_name,
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            CheckLintNameResult::NoTool => {
-                sess.emit_err(CheckNameUnknownTool {
-                    tool_name: tool_name.unwrap(),
-                    sub: RequestedLevel { level, lint_name },
-                });
-            }
-            _ => {}
-        };
-    }
-
     /// True if this symbol represents a lint group name.
     pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
         debug!(
@@ -1402,14 +1346,3 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
         err
     }
 }
-
-pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
-    match lint_name.split_once("::") {
-        Some((tool_name, lint_name)) => {
-            let tool_name = Symbol::intern(tool_name);
-
-            (Some(tool_name), lint_name)
-        }
-        None => (None, lint_name),
-    }
-}
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 607875b3faa..eccea35c702 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,7 +1,5 @@
 use crate::fluent_generated as fluent;
-use rustc_errors::{
-    AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage,
-};
+use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
@@ -102,29 +100,6 @@ pub struct UnsupportedGroup {
     pub lint_group: String,
 }
 
-pub struct CheckNameUnknown<'a> {
-    pub lint_name: &'a str,
-    pub suggestion: Option<Symbol>,
-    pub sub: RequestedLevel<'a>,
-}
-
-impl IntoDiagnostic<'_> for CheckNameUnknown<'_> {
-    fn into_diagnostic(
-        self,
-        handler: &Handler,
-    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
-        diag.code(rustc_errors::error_code!(E0602));
-        if let Some(suggestion) = self.suggestion {
-            diag.help(fluent::lint_help);
-            diag.set_arg("suggestion", suggestion);
-        }
-        diag.set_arg("lint_name", self.lint_name);
-        diag.subdiagnostic(self.sub);
-        diag
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag(lint_check_name_unknown_tool, code = "E0602")]
 pub struct CheckNameUnknownTool<'a> {
@@ -132,30 +107,3 @@ pub struct CheckNameUnknownTool<'a> {
     #[subdiagnostic]
     pub sub: RequestedLevel<'a>,
 }
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_renamed)]
-pub struct CheckNameRenamed<'a> {
-    pub lint_name: &'a str,
-    pub replace: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_removed)]
-pub struct CheckNameRemoved<'a> {
-    pub lint_name: &'a str,
-    pub reason: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
-
-#[derive(Diagnostic)]
-#[diag(lint_check_name_deprecated)]
-pub struct CheckNameDeprecated<'a> {
-    pub lint_name: &'a str,
-    pub new_name: &'a str,
-    #[subdiagnostic]
-    pub sub: RequestedLevel<'a>,
-}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 73af51d9e90..b24186ae1aa 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -21,7 +21,6 @@ use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit as hir_visit;
-use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
@@ -61,6 +60,9 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
         self.context.last_node_with_lint_attrs = id;
         debug!("late context: enter_attrs({:?})", attrs);
         lint_callback!(self, enter_lint_attrs, attrs);
+        for attr in attrs {
+            lint_callback!(self, check_attribute, attr);
+        }
         f(self);
         debug!("late context: exit_attrs({:?})", attrs);
         lint_callback!(self, exit_lint_attrs, attrs);
@@ -377,20 +379,18 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
 
     let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
 
-    // There is no module lint that will have the crate itself as an item, so check it here.
-    if hir_id == hir::CRATE_HIR_ID {
-        lint_callback!(cx, check_crate,);
-    }
+    cx.with_lint_attrs(hir_id, |cx| {
+        // There is no module lint that will have the crate itself as an item, so check it here.
+        if hir_id == hir::CRATE_HIR_ID {
+            lint_callback!(cx, check_crate,);
+        }
 
-    cx.process_mod(module, hir_id);
+        cx.process_mod(module, hir_id);
 
-    // Visit the crate attributes
-    if hir_id == hir::CRATE_HIR_ID {
-        for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
-            cx.visit_attribute(attr)
+        if hir_id == hir::CRATE_HIR_ID {
+            lint_callback!(cx, check_crate_post,);
         }
-        lint_callback!(cx, check_crate_post,);
-    }
+    });
 }
 
 fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
@@ -431,7 +431,6 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
         // item), warn for it here.
         lint_callback!(cx, check_crate,);
         tcx.hir().walk_toplevel_module(cx);
-        tcx.hir().walk_attributes(cx);
         lint_callback!(cx, check_crate_post,);
     })
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index f58782c0f22..df67cf5d12f 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,3 +1,8 @@
+use crate::errors::{CheckNameUnknownTool, RequestedLevel, UnsupportedGroup};
+use crate::lints::{
+    DeprecatedLintNameFromCommandLine, RemovedLintFromCommandLine, RenamedLintFromCommandLine,
+    UnknownLintFromCommandLine,
+};
 use crate::{
     builtin::MISSING_DOCS,
     context::{CheckLintNameResult, LintStore},
@@ -552,12 +557,55 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
     fn add_command_line(&mut self) {
         for &(ref lint_name, level) in &self.sess.opts.lint_opts {
-            self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools);
+            // Checks the validity of lint names derived from the command line.
+            let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
+            if lint_name_only == crate::WARNINGS.name_lower()
+                && matches!(level, Level::ForceWarn(_))
+            {
+                self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
+            }
+            match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
+                CheckLintNameResult::Renamed(ref replace) => {
+                    let name = lint_name.as_str();
+                    let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = RenamedLintFromCommandLine { name, suggestion, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::Removed(ref reason) => {
+                    let name = lint_name.as_str();
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = RemovedLintFromCommandLine { name, reason, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::NoLint(suggestion) => {
+                    let name = lint_name.clone();
+                    let suggestion =
+                        suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace });
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
+                    self.emit_lint(UNKNOWN_LINTS, lint);
+                }
+                CheckLintNameResult::Tool(Err((Some(_), ref replace))) => {
+                    let name = lint_name.clone();
+                    let requested_level = RequestedLevel { level, lint_name };
+                    let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level };
+                    self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
+                }
+                CheckLintNameResult::NoTool => {
+                    self.sess.emit_err(CheckNameUnknownTool {
+                        tool_name: tool_name.unwrap(),
+                        sub: RequestedLevel { level, lint_name },
+                    });
+                }
+                _ => {}
+            };
+
             let orig_level = level;
             let lint_flag_val = Symbol::intern(lint_name);
 
             let Ok(ids) = self.store.find_lints(&lint_name) else {
-                // errors handled in check_lint_name_cmdline above
+                // errors already handled above
                 continue;
             };
             for id in ids {
@@ -915,24 +963,18 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
                     _ if !self.warn_about_weird_lints => {}
 
-                    CheckLintNameResult::Renamed(new_name) => {
+                    CheckLintNameResult::Renamed(ref replace) => {
                         let suggestion =
-                            RenamedLintSuggestion { suggestion: sp, replace: new_name.as_str() };
+                            RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
                         let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
-                        self.emit_spanned_lint(
-                            RENAMED_AND_REMOVED_LINTS,
-                            sp.into(),
-                            RenamedLint { name: name.as_str(), suggestion },
-                        );
+                        let lint = RenamedLint { name: name.as_str(), suggestion };
+                        self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
                     }
 
-                    CheckLintNameResult::Removed(reason) => {
+                    CheckLintNameResult::Removed(ref reason) => {
                         let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
-                        self.emit_spanned_lint(
-                            RENAMED_AND_REMOVED_LINTS,
-                            sp.into(),
-                            RemovedLint { name: name.as_str(), reason: reason.as_str() },
-                        );
+                        let lint = RemovedLint { name: name.as_str(), reason };
+                        self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
                     }
 
                     CheckLintNameResult::NoLint(suggestion) => {
@@ -941,13 +983,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                         } else {
                             name.to_string()
                         };
-                        let suggestion = suggestion
-                            .map(|replace| UnknownLintSuggestion { suggestion: sp, replace });
-                        self.emit_spanned_lint(
-                            UNKNOWN_LINTS,
-                            sp.into(),
-                            UnknownLint { name, suggestion },
-                        );
+                        let suggestion = suggestion.map(|replace| {
+                            UnknownLintSuggestion::WithSpan { suggestion: sp, replace }
+                        });
+                        let lint = UnknownLint { name, suggestion };
+                        self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint);
                     }
                 }
                 // If this lint was renamed, apply the new lint instead of ignoring the attribute.
@@ -1092,3 +1132,14 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers };
 }
+
+pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
+    match lint_name.split_once("::") {
+        Some((tool_name, lint_name)) => {
+            let tool_name = Symbol::intern(tool_name);
+
+            (Some(tool_name), lint_name)
+        }
+        None => (None, lint_name),
+    }
+}
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0e942d774a7..3e26d6dc32d 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2,6 +2,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 use std::num::NonZeroU32;
 
+use crate::errors::RequestedLevel;
 use crate::fluent_generated as fluent;
 use rustc_errors::{
     AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString,
@@ -1013,6 +1014,16 @@ pub struct DeprecatedLintName<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_deprecated_lint_name)]
+#[help]
+pub struct DeprecatedLintNameFromCommandLine<'a> {
+    pub name: String,
+    pub replace: &'a str,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_renamed_lint)]
 pub struct RenamedLint<'a> {
     pub name: &'a str,
@@ -1021,11 +1032,25 @@ pub struct RenamedLint<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
-pub struct RenamedLintSuggestion<'a> {
-    #[primary_span]
-    pub suggestion: Span,
-    pub replace: &'a str,
+pub enum RenamedLintSuggestion<'a> {
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
+    WithSpan {
+        #[primary_span]
+        suggestion: Span,
+        replace: &'a str,
+    },
+    #[help(lint_help)]
+    WithoutSpan { replace: &'a str },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_renamed_lint)]
+pub struct RenamedLintFromCommandLine<'a> {
+    pub name: &'a str,
+    #[subdiagnostic]
+    pub suggestion: RenamedLintSuggestion<'a>,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
 }
 
 #[derive(LintDiagnostic)]
@@ -1036,6 +1061,15 @@ pub struct RemovedLint<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_removed_lint)]
+pub struct RemovedLintFromCommandLine<'a> {
+    pub name: &'a str,
+    pub reason: &'a str,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unknown_lint)]
 pub struct UnknownLint {
     pub name: String,
@@ -1044,11 +1078,25 @@ pub struct UnknownLint {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
-pub struct UnknownLintSuggestion {
-    #[primary_span]
-    pub suggestion: Span,
-    pub replace: Symbol,
+pub enum UnknownLintSuggestion {
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    WithSpan {
+        #[primary_span]
+        suggestion: Span,
+        replace: Symbol,
+    },
+    #[help(lint_help)]
+    WithoutSpan { replace: Symbol },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_lint, code = "E0602")]
+pub struct UnknownLintFromCommandLine<'a> {
+    pub name: String,
+    #[subdiagnostic]
+    pub suggestion: Option<UnknownLintSuggestion>,
+    #[subdiagnostic]
+    pub requested_level: RequestedLevel<'a>,
 }
 
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 883f6242b56..d540f473ae8 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -128,7 +128,11 @@ fn is_operation_we_care_about<'tcx>(
 fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
     let e = e.peel_blocks();
 
-    fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    fn from_casts<'tcx>(
+        cx: &LateContext<'tcx>,
+        e: &'tcx Expr<'tcx>,
+        need_check_freeze: &mut bool,
+    ) -> Option<&'tcx Expr<'tcx>> {
         // <expr> as *mut ...
         let mut e = if let ExprKind::Cast(e, t) = e.kind
             && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
@@ -138,6 +142,14 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
             && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
             && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
             expr
+        // UnsafeCell::raw_get(<expr>)
+        } else if let ExprKind::Call(path, [arg]) = e.kind
+            && let ExprKind::Path(ref qpath) = path.kind
+            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+            && cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id)
+        {
+            *need_check_freeze = true;
+            arg
         } else {
             return None;
         };
@@ -160,11 +172,18 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
             {
                 had_at_least_one_cast = true;
                 expr
-            // ptr::from_ref(<expr>)
+            // ptr::from_ref(<expr>) or UnsafeCell::raw_get(<expr>)
             } else if let ExprKind::Call(path, [arg]) = e.kind
                 && let ExprKind::Path(ref qpath) = path.kind
                 && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-                && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
+                && matches!(
+                    cx.tcx.get_diagnostic_name(def_id),
+                    Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get)
+                )
+            {
+                if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) {
+                    *need_check_freeze = true;
+                }
                 return Some(arg);
             } else if had_at_least_one_cast {
                 return Some(e);
@@ -190,10 +209,25 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
         }
     }
 
-    let Some(e) = from_casts(cx, e).or_else(|| from_transmute(cx, e)) else {
+    let mut need_check_freeze = false;
+    let Some(e) = from_casts(cx, e, &mut need_check_freeze).or_else(|| from_transmute(cx, e))
+    else {
         return false;
     };
 
     let e = e.peel_blocks();
-    matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not))
+    let node_type = cx.typeck_results().node_type(e.hir_id);
+    if let ty::Ref(_, inner_ty, Mutability::Not) = node_type.kind() {
+        // If an UnsafeCell method is involved we need to additionaly check the
+        // inner type for the presence of the Freeze trait (ie does NOT contain
+        // an UnsafeCell), since in that case we would incorrectly lint on valid casts.
+        //
+        // We also consider non concrete skeleton types (ie generics)
+        // to be an issue since there is no way to make it safe for abitrary types.
+        !need_check_freeze
+            || inner_ty.is_freeze(cx.tcx, cx.param_env)
+            || !inner_ty.has_concrete_skeleton()
+    } else {
+        false
+    }
 }
diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs
index fc9d6f636b2..4fd054cb717 100644
--- a/compiler/rustc_lint/src/tests.rs
+++ b/compiler/rustc_lint/src/tests.rs
@@ -1,4 +1,4 @@
-use crate::context::parse_lint_and_tool_name;
+use crate::levels::parse_lint_and_tool_name;
 use rustc_span::{create_default_session_globals_then, Symbol};
 
 #[test]
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 56508a2a6cc..e812493b3dd 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
             };
             let def_id = trait_predicate.trait_ref.def_id;
             if cx.tcx.lang_items().drop_trait() == Some(def_id) {
-                // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern.
+                // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern.
                 if trait_predicate.trait_ref.self_ty().is_impl_trait() {
                     continue;
                 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fc4c29eb36d..57c2e289f20 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -917,13 +917,18 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
         // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
         // If the computed size for the field and the enum are different, the nonnull optimization isn't
         // being applied (and we've got a problem somewhere).
-        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap();
-        if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
+        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).ok();
+        if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) {
             bug!("improper_ctypes: Option nonnull optimization not applied?");
         }
 
         // Return the nullable type this Option-like enum can be safely represented with.
-        let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
+        let field_ty_layout = tcx.layout_of(param_env.and(field_ty));
+        if field_ty_layout.is_err() && !field_ty.has_non_region_param() {
+            bug!("should be able to compute the layout of non-polymorphic type");
+        }
+
+        let field_ty_abi = &field_ty_layout.ok()?.abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
             match field_ty_scalar.valid_range(&tcx) {
                 WrappingRange { start: 0, end }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7e745de4f1a..2567e273e11 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3381,6 +3381,7 @@ declare_lint_pass! {
         PROC_MACRO_BACK_COMPAT,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+        REFINING_IMPL_TRAIT,
         RENAMED_AND_REMOVED_LINTS,
         REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
         RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
@@ -4363,7 +4364,7 @@ declare_lint! {
     ///     pub struct S;
     /// }
     ///
-    /// pub fn get_voldemort() -> m::S { m::S }
+    /// pub fn get_unnameable() -> m::S { m::S }
     /// # fn main() {}
     /// ```
     ///
@@ -4448,7 +4449,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
-    ///
     /// #![deny(ambiguous_glob_imports)]
     /// pub fn foo() -> u32 {
     ///     use sub::*;
@@ -4485,6 +4485,50 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `refining_impl_trait` lint detects usages of return-position impl
+    /// traits in trait signatures which are refined by implementations.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(return_position_impl_trait_in_trait)]
+    /// #![deny(refining_impl_trait)]
+    ///
+    /// use std::fmt::Display;
+    ///
+    /// pub trait AsDisplay {
+    ///     fn as_display(&self) -> impl Display;
+    /// }
+    ///
+    /// impl<'s> AsDisplay for &'s str {
+    ///     fn as_display(&self) -> Self {
+    ///         *self
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     // users can observe that the return type of
+    ///     // `<&str as AsDisplay>::as_display()` is `&str`.
+    ///     let x: &str = "".as_display();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Return-position impl trait in traits (RPITITs) desugar to associated types,
+    /// and callers of methods for types where the implementation is known are
+    /// able to observe the types written in the impl signature. This may be
+    /// intended behavior, but may also pose a semver hazard for authors of libraries
+    /// who do not wish to make stronger guarantees about the types than what is
+    /// written in the trait signature.
+    pub REFINING_IMPL_TRAIT,
+    Warn,
+    "impl trait in impl method signature does not match trait method signature",
+}
+
+declare_lint! {
     /// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes
     /// that were erroneously allowed in associated constants.
     ///
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 8f8f1d8c04f..fefb1e0fbe0 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1,5 +1,6 @@
 #include <stdio.h>
 
+#include <cstddef>
 #include <iomanip>
 #include <vector>
 #include <set>
@@ -9,6 +10,7 @@
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/CommandFlags.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/AssemblyAnnotationWriter.h"
@@ -50,6 +52,8 @@
 
 using namespace llvm;
 
+static codegen::RegisterCodeGenFlags CGF;
+
 typedef struct LLVMOpaquePass *LLVMPassRef;
 typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
 
@@ -406,7 +410,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool RelaxELFRelocations,
     bool UseInitArray,
     const char *SplitDwarfFile,
-    bool ForceEmulatedTls) {
+    const char *DebugInfoCompression,
+    bool ForceEmulatedTls,
+    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -421,7 +427,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     return nullptr;
   }
 
-  TargetOptions Options;
+  TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Trip);
 
   Options.FloatABIType = FloatABI::Default;
   if (UseSoftFloat) {
@@ -436,6 +442,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   if (SplitDwarfFile) {
       Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
   }
+#if LLVM_VERSION_GE(16, 0)
+  if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
+    Options.CompressDebugSections = DebugCompressionType::Zlib;
+  } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
+    Options.CompressDebugSections = DebugCompressionType::Zstd;
+  } else if (!strcmp("none", DebugInfoCompression)) {
+    Options.CompressDebugSections = DebugCompressionType::None;
+  }
+#endif
+
   Options.RelaxELFRelocations = RelaxELFRelocations;
   Options.UseInitArray = UseInitArray;
 
@@ -462,12 +478,48 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
 
   Options.EmitStackSizeSection = EmitStackSizeSection;
 
+
+  if (ArgsCstrBuff != nullptr)
+  {
+    int buffer_offset = 0;
+    assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
+
+    const size_t arg0_len = std::strlen(ArgsCstrBuff);
+    char* arg0 = new char[arg0_len + 1];
+    memcpy(arg0, ArgsCstrBuff, arg0_len);
+    arg0[arg0_len] = '\0';
+    buffer_offset += arg0_len + 1;
+
+    const int num_cmd_arg_strings =
+      std::count(&ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0');
+
+    std::string* cmd_arg_strings = new std::string[num_cmd_arg_strings];
+    for (int i = 0; i < num_cmd_arg_strings; ++i)
+    {
+      assert(buffer_offset < ArgsCstrBuffLen);
+      const int len = std::strlen(ArgsCstrBuff + buffer_offset);
+      cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len);
+      buffer_offset += len + 1;
+    }
+
+    assert(buffer_offset == ArgsCstrBuffLen);
+
+    Options.MCOptions.Argv0 = arg0;
+    Options.MCOptions.CommandLineArgs =
+      llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings);
+  }
+
   TargetMachine *TM = TheTarget->createTargetMachine(
       Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel);
   return wrap(TM);
 }
 
 extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
+
+  MCTargetOptions& MCOptions = unwrap(TM)->Options.MCOptions;
+  delete[] MCOptions.Argv0;
+  delete[] MCOptions.CommandLineArgs.data();
+
   delete unwrap(TM);
 }
 
@@ -1058,6 +1110,13 @@ extern "C" void LLVMRustPrintPasses() {
 extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
                                            size_t Len) {
   auto PreserveFunctions = [=](const GlobalValue &GV) {
+    // Preserve LLVM-injected, ASAN-related symbols.
+    // See also https://github.com/rust-lang/rust/issues/113404.
+    if (GV.getName() == "___asan_globals_registered") {
+      return true;
+    }
+
+    // Preserve symbols exported from Rust modules.
     for (size_t I = 0; I < Len; I++) {
       if (GV.getName() == Symbols[I]) {
         return true;
@@ -1511,6 +1570,38 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data,
   return BitcodeOrError->getBufferStart();
 }
 
+// Find a section of an object file by name. Fail if the section is missing or
+// empty.
+extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
+                                                            size_t len,
+                                                            const char *name,
+                                                            size_t *out_len) {
+  *out_len = 0;
+  StringRef Data(data, len);
+  MemoryBufferRef Buffer(Data, ""); // The id is unused.
+  file_magic Type = identify_magic(Buffer.getBuffer());
+  Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError =
+      object::ObjectFile::createObjectFile(Buffer, Type);
+  if (!ObjFileOrError) {
+    LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str());
+    return nullptr;
+  }
+  for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
+    Expected<StringRef> Name = Sec.getName();
+    if (Name && *Name == name) {
+      Expected<StringRef> SectionOrError = Sec.getContents();
+      if (!SectionOrError) {
+        LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
+        return nullptr;
+      }
+      *out_len = SectionOrError->size();
+      return SectionOrError->data();
+    }
+  }
+  LLVMRustSetLastError("could not find requested section");
+  return nullptr;
+}
+
 // Computes the LTO cache key for the provided 'ModId' in the given 'Data',
 // storing the result in 'KeyOut'.
 // Currently, this cache key is a SHA-1 hash of anything that could affect
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 70cdf3d6d23..4390486b0de 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
   }
   return false;
 }
+
+extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
+#if LLVM_VERSION_GE(16, 0)
+  return llvm::compression::zlib::isAvailable();
+#else
+  return false;
+#endif
+}
+
+extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
+#if LLVM_VERSION_GE(16, 0)
+  return llvm::compression::zstd::isAvailable();
+#else
+  return false;
+#endif
+}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index fce80ab37dd..69221475356 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -8,7 +8,7 @@ use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, All
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
+use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
@@ -134,14 +134,14 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
 }
 
 impl CStore {
-    pub fn from_tcx(tcx: TyCtxt<'_>) -> MappedReadGuard<'_, CStore> {
-        ReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
+    pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
+        FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
             cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
         })
     }
 
-    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> MappedWriteGuard<'_, CStore> {
-        WriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
+    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {
+        FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
             cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
         })
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index aeda8af6d2c..f964a8c76c0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -131,7 +131,7 @@ macro_rules! provide_one {
                 $tcx.ensure().crate_hash($def_id.krate);
             }
 
-            let cdata = rustc_data_structures::sync::MappedReadGuard::map(CStore::from_tcx($tcx), |c| {
+            let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {
                 c.get_crate_data($def_id.krate).cdata
             });
             let $cdata = crate::creader::CrateMetadataRef {
@@ -510,7 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
         crates: |tcx, ()| {
             // The list of loaded crates is now frozen in query cache,
             // so make sure cstore is not mutably accessed from here on.
-            tcx.untracked().cstore.leak();
+            tcx.untracked().cstore.freeze();
             tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
         },
         ..*providers
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 4f4351633a2..cc7ae932e11 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -14,7 +14,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{
-    CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
+    CrateNum, DefId, DefIndex, LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX,
+    LOCAL_CRATE,
 };
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::lang_items::LangItem;
@@ -50,7 +51,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::FileEncoder,
     tcx: TyCtxt<'tcx>,
     feat: &'tcx rustc_feature::Features,
-
     tables: TableBuilders,
 
     lazy_state: LazyState,
@@ -280,8 +280,8 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
             // All of this logic ensures that the final result of deserialization is a 'normal'
             // Span that can be used without any additional trouble.
             let metadata_index = {
-                // Introduce a new scope so that we drop the 'lock()' temporary
-                match &*source_file.external_src.lock() {
+                // Introduce a new scope so that we drop the 'read()' temporary
+                match &*source_file.external_src.read() {
                     ExternalSource::Foreign { metadata_index, .. } => *metadata_index,
                     src => panic!("Unexpected external source {src:?}"),
                 }
@@ -1002,15 +1002,31 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
     }
 }
 
-/// Whether we should encode MIR.
+/// Whether we should encode MIR. Return a pair, resp. for CTFE and for LLVM.
 ///
 /// Computing, optimizing and encoding the MIR is a relatively expensive operation.
 /// We want to avoid this work when not required. Therefore:
 /// - we only compute `mir_for_ctfe` on items with const-eval semantics;
 /// - we skip `optimized_mir` for check runs.
+/// - we only encode `optimized_mir` that could be generated in other crates, that is, a code that
+///   is either generic or has inline hint, and is reachable from the other crates (contained
+///   in reachable set).
+///
+/// Note: Reachable set describes definitions that might be generated or referenced from other
+/// crates and it can be used to limit optimized MIR that needs to be encoded. On the other hand,
+/// the reachable set doesn't have much to say about which definitions might be evaluated at compile
+/// time in other crates, so it cannot be used to omit CTFE MIR. For example, `f` below is
+/// unreachable and yet it can be evaluated in other crates:
 ///
-/// Return a pair, resp. for CTFE and for LLVM.
-fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
+/// ```
+/// const fn f() -> usize { 0 }
+/// pub struct S { pub a: [usize; f()] }
+/// ```
+fn should_encode_mir(
+    tcx: TyCtxt<'_>,
+    reachable_set: &LocalDefIdSet,
+    def_id: LocalDefId,
+) -> (bool, bool) {
     match tcx.def_kind(def_id) {
         // Constructors
         DefKind::Ctor(_, _) => {
@@ -1027,14 +1043,15 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
         // Full-fledged functions + closures
         DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
             let generics = tcx.generics_of(def_id);
-            let needs_inline = (generics.requires_monomorphization(tcx)
-                || tcx.codegen_fn_attrs(def_id).requests_inline())
-                && tcx.sess.opts.output_types.should_codegen();
+            let opt = tcx.sess.opts.unstable_opts.always_encode_mir
+                || (tcx.sess.opts.output_types.should_codegen()
+                    && reachable_set.contains(&def_id)
+                    && (generics.requires_monomorphization(tcx)
+                        || tcx.codegen_fn_attrs(def_id).requests_inline()));
             // The function has a `const` modifier or is in a `#[const_trait]`.
             let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
                 || tcx.is_const_default_method(def_id.to_def_id());
-            let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
-            (is_const_fn, needs_inline || always_encode_mir)
+            (is_const_fn, opt)
         }
         // Generators require optimized MIR to compute layout.
         DefKind::Generator => (false, true),
@@ -1580,9 +1597,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
 
         let tcx = self.tcx;
+        let reachable_set = tcx.reachable_set(());
 
         let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| {
-            let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+            let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
             if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None }
         });
         for (def_id, encode_const, encode_opt) in keys_and_jobs {
@@ -2067,8 +2085,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
         return;
     }
 
+    let reachable_set = tcx.reachable_set(());
     par_for_each_in(tcx.mir_keys(()), |&def_id| {
-        let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+        let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
 
         if encode_const {
             tcx.ensure_with_value().mir_for_ctfe(def_id);
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index afcf08395bb..78a0f82db13 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -97,7 +97,7 @@ macro_rules! define_dep_nodes {
             // discriminants of the variants have been assigned consecutively from 0
             // so that just the one comparison suffices to check that the u16 can be
             // transmuted to a DepKind.
-            const VARIANTS: u16 = {
+            pub const VARIANTS: u16 = {
                 let deps: &[DepKind] = &[$(DepKind::$variant,)*];
                 let mut i = 0;
                 while i < deps.len() {
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index f79ce08b8ae..87436f9eeed 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -26,6 +26,7 @@ pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCt
 impl rustc_query_system::dep_graph::DepKind for DepKind {
     const NULL: Self = DepKind::Null;
     const RED: Self = DepKind::Red;
+    const MAX: u16 = DepKind::VARIANTS - 1;
 
     fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}(", node.kind)?;
@@ -68,6 +69,21 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
             op(icx.task_deps)
         })
     }
+
+    #[track_caller]
+    #[inline]
+    fn from_u16(u: u16) -> Self {
+        if u > Self::MAX {
+            panic!("Invalid DepKind {u}");
+        }
+        // SAFETY: See comment on DepKind::VARIANTS
+        unsafe { std::mem::transmute(u) }
+    }
+
+    #[inline]
+    fn to_u16(self) -> u16 {
+        self as u16
+    }
 }
 
 impl<'tcx> DepContext for TyCtxt<'tcx> {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 3e8f07ed233..f67f8015c04 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1206,8 +1206,8 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
         upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
         source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
         debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
-        if tcx.sess.opts.incremental_relative_spans() {
-            let definitions = tcx.definitions_untracked();
+        if tcx.sess.opts.incremental.is_some() {
+            let definitions = tcx.untracked().definitions.freeze();
             let mut owner_spans: Vec<_> = krate
                 .owners
                 .iter_enumerated()
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 81823118ab8..b17f1512886 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -27,6 +27,7 @@ use crate::ty::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
+use std::fmt::Display;
 use std::ops::Index;
 
 /// A "canonicalized" type `V` is one where all free inference
@@ -40,6 +41,16 @@ pub struct Canonical<'tcx, V> {
     pub variables: CanonicalVarInfos<'tcx>,
 }
 
+impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
+            self.value, self.max_universe, self.variables
+        )
+    }
+}
+
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
 impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
@@ -173,6 +184,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::PlaceholderRegion(..) => false,
             CanonicalVarKind::Const(..) => true,
             CanonicalVarKind::PlaceholderConst(_, _) => false,
+            CanonicalVarKind::Effect => true,
         }
     }
 
@@ -182,7 +194,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::Ty(_)
             | CanonicalVarKind::PlaceholderTy(_)
             | CanonicalVarKind::Const(_, _)
-            | CanonicalVarKind::PlaceholderConst(_, _) => false,
+            | CanonicalVarKind::PlaceholderConst(_, _)
+            | CanonicalVarKind::Effect => false,
         }
     }
 
@@ -190,7 +203,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
         match self.kind {
             CanonicalVarKind::Ty(_)
             | CanonicalVarKind::Region(_)
-            | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"),
+            | CanonicalVarKind::Const(_, _)
+            | CanonicalVarKind::Effect => bug!("expected placeholder: {self:?}"),
 
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
@@ -222,6 +236,9 @@ pub enum CanonicalVarKind<'tcx> {
     /// Some kind of const inference variable.
     Const(ty::UniverseIndex, Ty<'tcx>),
 
+    /// Effect variable `'?E`.
+    Effect,
+
     /// A "placeholder" that represents "any const".
     PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
 }
@@ -229,11 +246,11 @@ pub enum CanonicalVarKind<'tcx> {
 impl<'tcx> CanonicalVarKind<'tcx> {
     pub fn universe(self) -> ty::UniverseIndex {
         match self {
-            CanonicalVarKind::Ty(kind) => match kind {
-                CanonicalTyVarKind::General(ui) => ui,
-                CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
-            },
-
+            CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
+            CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
+                ty::UniverseIndex::ROOT
+            }
+            CanonicalVarKind::Effect => ty::UniverseIndex::ROOT,
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
@@ -248,15 +265,14 @@ impl<'tcx> CanonicalVarKind<'tcx> {
     /// the updated universe is not the root.
     pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
         match self {
-            CanonicalVarKind::Ty(kind) => match kind {
-                CanonicalTyVarKind::General(_) => {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
-                }
-                CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
-                    assert_eq!(ui, ty::UniverseIndex::ROOT);
-                    CanonicalVarKind::Ty(kind)
-                }
-            },
+            CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
+                CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
+            }
+            CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
+            | CanonicalVarKind::Effect => {
+                assert_eq!(ui, ty::UniverseIndex::ROOT);
+                self
+            }
             CanonicalVarKind::PlaceholderTy(placeholder) => {
                 CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
             }
@@ -443,6 +459,13 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                             };
                             ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
                         }
+                        CanonicalVarKind::Effect => ty::Const::new_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            tcx.types.bool,
+                        )
+                        .into(),
                         CanonicalVarKind::Const(_, ty)
                         | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
                             tcx,
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 85fb9214d9d..7ca9647590a 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -188,3 +188,53 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
         })
     }
 }
+
+/// values for the effect inference variable
+#[derive(Clone, Copy, Debug)]
+pub enum EffectVarValue<'tcx> {
+    /// The host effect is on, enabling access to syscalls, filesystem access, etc.
+    Host,
+    /// The host effect is off. Execution is restricted to const operations only.
+    NoHost,
+    Const(ty::Const<'tcx>),
+}
+
+impl<'tcx> EffectVarValue<'tcx> {
+    pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
+        match self {
+            EffectVarValue::Host => tcx.consts.true_,
+            EffectVarValue::NoHost => tcx.consts.false_,
+            EffectVarValue::Const(c) => c,
+        }
+    }
+}
+
+impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
+    type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
+    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+        match (value1, value2) {
+            (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
+            (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
+            (EffectVarValue::NoHost | EffectVarValue::Host, _)
+            | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
+            (EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
+                bug!("equating two const variables, both of which have known values")
+            }
+        }
+    }
+}
+
+impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
+    type Value = Option<EffectVarValue<'tcx>>;
+    #[inline]
+    fn index(&self) -> u32 {
+        self.index
+    }
+    #[inline]
+    fn from_index(i: u32) -> Self {
+        ty::EffectVid { index: i, phantom: PhantomData }
+    }
+    fn tag() -> &'static str {
+        "EffectVid"
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 577cd20b74c..76ac2b2ac60 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -255,9 +255,16 @@ impl_into_diagnostic_arg_through_debug! {
 
 /// Error information for when the program caused Undefined Behavior.
 #[derive(Debug)]
-pub enum UndefinedBehaviorInfo<'a> {
+pub enum UndefinedBehaviorInfo<'tcx> {
     /// Free-form case. Only for errors that are never caught! Used by miri
     Ub(String),
+    // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
+    // dispatched
+    /// A custom (free-form) fluent-translated error, created by `err_ub_custom!`.
+    Custom(crate::error::CustomSubdiagnostic<'tcx>),
+    /// Validation error.
+    ValidationError(ValidationErrorInfo<'tcx>),
+
     /// Unreachable code was executed.
     Unreachable,
     /// A slice/array index projection went out-of-bounds.
@@ -319,12 +326,10 @@ pub enum UndefinedBehaviorInfo<'a> {
     UninhabitedEnumVariantWritten(VariantIdx),
     /// An uninhabited enum variant is projected.
     UninhabitedEnumVariantRead(VariantIdx),
-    /// Validation error.
-    ValidationError(ValidationErrorInfo<'a>),
-    // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
-    // dispatched
-    /// A custom (free-form) error, created by `err_ub_custom!`.
-    Custom(crate::error::CustomSubdiagnostic<'a>),
+    /// ABI-incompatible argument types.
+    AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+    /// ABI-incompatible return types.
+    AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
 }
 
 #[derive(Debug, Clone, Copy)]
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 6484c30167c..3d45b4bdc33 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -8,6 +8,7 @@ use crate::mir::interpret::{
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::print::with_no_trimmed_paths;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{self, List, Ty, TyCtxt};
@@ -1028,19 +1029,6 @@ pub enum VarDebugInfoContents<'tcx> {
     /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
     Place(Place<'tcx>),
     Const(Constant<'tcx>),
-    /// The user variable's data is split across several fragments,
-    /// each described by a `VarDebugInfoFragment`.
-    /// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
-    /// and LLVM's `DW_OP_LLVM_fragment` for more details on
-    /// the underlying debuginfo feature this relies on.
-    Composite {
-        /// Type of the original user variable.
-        /// This cannot contain a union or an enum.
-        ty: Ty<'tcx>,
-        /// All the parts of the original user variable, which ended
-        /// up in disjoint places, due to optimizations.
-        fragments: Vec<VarDebugInfoFragment<'tcx>>,
-    },
 }
 
 impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
@@ -1048,19 +1036,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
         match self {
             VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
             VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
-            VarDebugInfoContents::Composite { ty, fragments } => {
-                write!(fmt, "{ty:?}{{ ")?;
-                for f in fragments.iter() {
-                    write!(fmt, "{f:?}, ")?;
-                }
-                write!(fmt, "}}")
-            }
         }
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct VarDebugInfoFragment<'tcx> {
+    /// Type of the original user variable.
+    /// This cannot contain a union or an enum.
+    pub ty: Ty<'tcx>,
+
     /// Where in the composite user variable this fragment is,
     /// represented as a "projection" into the composite variable.
     /// At lower levels, this corresponds to a byte/bit range.
@@ -1071,29 +1056,10 @@ pub struct VarDebugInfoFragment<'tcx> {
     // to match on the discriminant, or by using custom type debuginfo
     // with non-overlapping variants for the composite variable.
     pub projection: Vec<PlaceElem<'tcx>>,
-
-    /// Where the data for this fragment can be found.
-    /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
-    pub contents: Place<'tcx>,
-}
-
-impl Debug for VarDebugInfoFragment<'_> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        for elem in self.projection.iter() {
-            match elem {
-                ProjectionElem::Field(field, _) => {
-                    write!(fmt, ".{:?}", field.index())?;
-                }
-                _ => bug!("unsupported fragment projection `{:?}`", elem),
-            }
-        }
-
-        write!(fmt, " => {:?}", self.contents)
-    }
 }
 
 /// Debug information pertaining to a user variable.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct VarDebugInfo<'tcx> {
     pub name: Symbol,
 
@@ -1102,6 +1068,13 @@ pub struct VarDebugInfo<'tcx> {
     /// (see `LocalDecl`'s `source_info` field for more details).
     pub source_info: SourceInfo,
 
+    /// The user variable's data is split across several fragments,
+    /// each described by a `VarDebugInfoFragment`.
+    /// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
+    /// and LLVM's `DW_OP_LLVM_fragment` for more details on
+    /// the underlying debuginfo feature this relies on.
+    pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>,
+
     /// Where the data for this user variable is to be found.
     pub value: VarDebugInfoContents<'tcx>,
 
@@ -1111,6 +1084,20 @@ pub struct VarDebugInfo<'tcx> {
     pub argument_index: Option<u16>,
 }
 
+impl Debug for VarDebugInfo<'_> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite {
+            pre_fmt_projection(&projection[..], fmt)?;
+            write!(fmt, "({}: {})", self.name, ty)?;
+            post_fmt_projection(&projection[..], fmt)?;
+        } else {
+            write!(fmt, "{}", self.name)?;
+        }
+
+        write!(fmt, " => {:?}", self.value)
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock
 
@@ -1575,7 +1562,7 @@ impl<V, T> ProjectionElem<V, T> {
 /// need neither the `V` parameter for `Index` nor the `T` for `Field`.
 pub type ProjectionKind = ProjectionElem<(), ()>;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct PlaceRef<'tcx> {
     pub local: Local,
     pub projection: &'tcx [PlaceElem<'tcx>],
@@ -1751,69 +1738,90 @@ impl<'tcx> PlaceRef<'tcx> {
     }
 }
 
+impl From<Local> for PlaceRef<'_> {
+    #[inline]
+    fn from(local: Local) -> Self {
+        PlaceRef { local, projection: &[] }
+    }
+}
+
 impl Debug for Place<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        for elem in self.projection.iter().rev() {
-            match elem {
-                ProjectionElem::OpaqueCast(_)
-                | ProjectionElem::Downcast(_, _)
-                | ProjectionElem::Field(_, _) => {
-                    write!(fmt, "(").unwrap();
-                }
-                ProjectionElem::Deref => {
-                    write!(fmt, "(*").unwrap();
-                }
-                ProjectionElem::Index(_)
-                | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. } => {}
-            }
-        }
+        self.as_ref().fmt(fmt)
+    }
+}
 
+impl Debug for PlaceRef<'_> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        pre_fmt_projection(self.projection, fmt)?;
         write!(fmt, "{:?}", self.local)?;
+        post_fmt_projection(self.projection, fmt)
+    }
+}
 
-        for elem in self.projection.iter() {
-            match elem {
-                ProjectionElem::OpaqueCast(ty) => {
-                    write!(fmt, " as {ty})")?;
-                }
-                ProjectionElem::Downcast(Some(name), _index) => {
-                    write!(fmt, " as {name})")?;
-                }
-                ProjectionElem::Downcast(None, index) => {
-                    write!(fmt, " as variant#{index:?})")?;
-                }
-                ProjectionElem::Deref => {
-                    write!(fmt, ")")?;
-                }
-                ProjectionElem::Field(field, ty) => {
-                    write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
-                }
-                ProjectionElem::Index(ref index) => {
-                    write!(fmt, "[{index:?}]")?;
-                }
-                ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
-                    write!(fmt, "[{offset:?} of {min_length:?}]")?;
-                }
-                ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
-                    write!(fmt, "[-{offset:?} of {min_length:?}]")?;
-                }
-                ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
-                    write!(fmt, "[{from:?}:]")?;
-                }
-                ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
-                    write!(fmt, "[:-{to:?}]")?;
-                }
-                ProjectionElem::Subslice { from, to, from_end: true } => {
-                    write!(fmt, "[{from:?}:-{to:?}]")?;
-                }
-                ProjectionElem::Subslice { from, to, from_end: false } => {
-                    write!(fmt, "[{from:?}..{to:?}]")?;
-                }
+fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
+    for &elem in projection.iter().rev() {
+        match elem {
+            ProjectionElem::OpaqueCast(_)
+            | ProjectionElem::Downcast(_, _)
+            | ProjectionElem::Field(_, _) => {
+                write!(fmt, "(").unwrap();
+            }
+            ProjectionElem::Deref => {
+                write!(fmt, "(*").unwrap();
             }
+            ProjectionElem::Index(_)
+            | ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. } => {}
         }
+    }
 
-        Ok(())
+    Ok(())
+}
+
+fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
+    for &elem in projection.iter() {
+        match elem {
+            ProjectionElem::OpaqueCast(ty) => {
+                write!(fmt, " as {ty})")?;
+            }
+            ProjectionElem::Downcast(Some(name), _index) => {
+                write!(fmt, " as {name})")?;
+            }
+            ProjectionElem::Downcast(None, index) => {
+                write!(fmt, " as variant#{index:?})")?;
+            }
+            ProjectionElem::Deref => {
+                write!(fmt, ")")?;
+            }
+            ProjectionElem::Field(field, ty) => {
+                with_no_trimmed_paths!(write!(fmt, ".{:?}: {})", field.index(), ty)?);
+            }
+            ProjectionElem::Index(ref index) => {
+                write!(fmt, "[{index:?}]")?;
+            }
+            ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
+                write!(fmt, "[{offset:?} of {min_length:?}]")?;
+            }
+            ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
+                write!(fmt, "[-{offset:?} of {min_length:?}]")?;
+            }
+            ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
+                write!(fmt, "[{from:?}:]")?;
+            }
+            ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
+                write!(fmt, "[:-{to:?}]")?;
+            }
+            ProjectionElem::Subslice { from, to, from_end: true } => {
+                write!(fmt, "[{from:?}:-{to:?}]")?;
+            }
+            ProjectionElem::Subslice { from, to, from_end: false } => {
+                write!(fmt, "[{from:?}..{to:?}]")?;
+            }
+        }
     }
+
+    Ok(())
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -2070,7 +2078,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
             Len(ref a) => write!(fmt, "Len({a:?})"),
             Cast(ref kind, ref place, ref ty) => {
-                write!(fmt, "{place:?} as {ty:?} ({kind:?})")
+                with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
             }
             BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
             CheckedBinaryOp(ref op, box (ref a, ref b)) => {
@@ -2078,11 +2086,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
             UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
             Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
-            NullaryOp(ref op, ref t) => match op {
-                NullOp::SizeOf => write!(fmt, "SizeOf({t:?})"),
-                NullOp::AlignOf => write!(fmt, "AlignOf({t:?})"),
-                NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t:?}, {fields:?})"),
-            },
+            NullaryOp(ref op, ref t) => {
+                let t = with_no_trimmed_paths!(format!("{}", t));
+                match op {
+                    NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
+                    NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
+                    NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
+                }
+            }
             ThreadLocalRef(did) => ty::tls::with(|tcx| {
                 let muta = tcx.static_mutability(did).unwrap().prefix_str();
                 write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
@@ -2218,7 +2229,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             }
 
             ShallowInitBox(ref place, ref ty) => {
-                write!(fmt, "ShallowInitBox({place:?}, {ty:?})")
+                with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
             }
         }
     }
@@ -2317,7 +2328,7 @@ impl<'tcx> ConstantKind<'tcx> {
 
     #[inline]
     pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
-        Some(self.try_to_scalar()?.assert_int())
+        self.try_to_scalar()?.try_to_int().ok()
     }
 
     #[inline]
@@ -3056,6 +3067,6 @@ mod size_asserts {
     static_assert_size!(StatementKind<'_>, 16);
     static_assert_size!(Terminator<'_>, 104);
     static_assert_size!(TerminatorKind<'_>, 88);
-    static_assert_size!(VarDebugInfo<'_>, 80);
+    static_assert_size!(VarDebugInfo<'_>, 88);
     // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 773056e8a17..6b23a7f5bff 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -554,10 +554,7 @@ fn write_scope_tree(
             continue;
         }
 
-        let indented_debug_info = format!(
-            "{0:1$}debug {2} => {3:?};",
-            INDENT, indent, var_debug_info.name, var_debug_info.value,
-        );
+        let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info);
 
         if tcx.sess.opts.unstable_opts.mir_include_spans {
             writeln!(
@@ -586,8 +583,10 @@ fn write_scope_tree(
 
         let mut_str = local_decl.mutability.prefix_str();
 
-        let mut indented_decl =
-            format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
+        let mut indented_decl = ty::print::with_no_trimmed_paths!(format!(
+            "{0:1$}let {2}{3:?}: {4}",
+            INDENT, indent, mut_str, local, local_decl.ty
+        ));
         if let Some(user_ty) = &local_decl.user_ty {
             for user_ty in user_ty.projections() {
                 write!(indented_decl, " as {user_ty:?}").unwrap();
@@ -1061,11 +1060,11 @@ fn write_user_type_annotations(
     for (index, annotation) in body.user_type_annotations.iter_enumerated() {
         writeln!(
             w,
-            "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
+            "| {:?}: user_ty: {}, span: {}, inferred_ty: {}",
             index.index(),
             annotation.user_ty,
             tcx.sess.source_map().span_to_embeddable_string(annotation.span),
-            annotation.inferred_ty,
+            with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)),
         )?;
     }
     if !body.user_type_annotations.is_empty() {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 87b04aabe6a..61244b94289 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -838,12 +838,20 @@ macro_rules! make_mir_visitor {
                 let VarDebugInfo {
                     name: _,
                     source_info,
+                    composite,
                     value,
                     argument_index: _,
                 } = var_debug_info;
 
                 self.visit_source_info(source_info);
                 let location = Location::START;
+                if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
+                    self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+                    for elem in projection {
+                        let ProjectionElem::Field(_, ty) = elem else { bug!() };
+                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+                    }
+                }
                 match value {
                     VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
                     VarDebugInfoContents::Place(place) =>
@@ -852,17 +860,6 @@ macro_rules! make_mir_visitor {
                             PlaceContext::NonUse(NonUseContext::VarDebugInfo),
                             location
                         ),
-                    VarDebugInfoContents::Composite { ty, fragments } => {
-                        // FIXME(eddyb) use a better `TyContext` here.
-                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
-                        for VarDebugInfoFragment { projection: _, contents } in fragments {
-                            self.visit_place(
-                                contents,
-                                PlaceContext::NonUse(NonUseContext::VarDebugInfo),
-                                location,
-                            );
-                        }
-                    }
                 }
             }
 
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 64853bd9612..280f5d0a84c 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -692,7 +692,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
         let len = BytePos::decode(decoder);
 
         let file_lo = decoder.file_index_to_file(file_lo_index);
-        let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
+        let lo = file_lo.lines()[line_lo - 1] + col_lo;
         let lo = file_lo.absolute_position(lo);
         let hi = lo + len;
 
@@ -896,7 +896,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
         }
 
         if let Some(parent) = span_data.parent {
-            let enclosing = s.tcx.source_span(parent).data_untracked();
+            let enclosing = s.tcx.source_span_untracked(parent).data_untracked();
             if enclosing.contains(span_data) {
                 TAG_RELATIVE_SPAN.encode(s);
                 (span_data.lo - enclosing.lo).to_u32().encode(s);
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index b16163edf14..9d99344d5bd 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -227,6 +227,11 @@ impl ScalarInt {
     }
 
     #[inline]
+    pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
+        Self::try_from_uint(i, tcx.data_layout.pointer_size)
+    }
+
+    #[inline]
     pub fn assert_bits(self, target_size: Size) -> u128 {
         self.to_bits(target_size).unwrap_or_else(|size| {
             bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index db4a15fbee5..17fbbd7c6b7 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -55,6 +55,11 @@ static_assert_size!(super::ConstKind<'_>, 32);
 pub enum InferConst<'tcx> {
     /// Infer the value of the const.
     Var(ty::ConstVid<'tcx>),
+    /// Infer the value of the effect.
+    ///
+    /// For why this is separate from the `Var` variant above, see the
+    /// documentation on `EffectVid`.
+    EffectVar(ty::EffectVid<'tcx>),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
 }
@@ -62,7 +67,9 @@ pub enum InferConst<'tcx> {
 impl<CTX> HashStable<CTX> for InferConst<'_> {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         match self {
-            InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+            InferConst::Var(_) | InferConst::EffectVar(_) => {
+                panic!("const variables should not be hashed: {self:?}")
+            }
             InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e2f9e299566..eeb87d5561d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -39,7 +39,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal};
+use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{
     DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
@@ -964,8 +964,8 @@ impl<'tcx> TyCtxt<'tcx> {
                 i += 1;
             }
 
-            // Leak a read lock once we finish iterating on definitions, to prevent adding new ones.
-            definitions.leak();
+            // Freeze definitions once we finish iterating on them, to prevent adding new ones.
+            definitions.freeze();
         })
     }
 
@@ -974,10 +974,9 @@ impl<'tcx> TyCtxt<'tcx> {
         // definitions change.
         self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
 
-        // Leak a read lock once we start iterating on definitions, to prevent adding new ones
+        // Freeze definitions once we start iterating on them, to prevent adding new ones
         // while iterating. If some query needs to add definitions, it should be `ensure`d above.
-        let definitions = self.untracked.definitions.leak();
-        definitions.def_path_table()
+        self.untracked.definitions.freeze().def_path_table()
     }
 
     pub fn def_path_hash_to_def_index_map(
@@ -986,17 +985,16 @@ impl<'tcx> TyCtxt<'tcx> {
         // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
         self.ensure().hir_crate(());
-        // Leak a read lock once we start iterating on definitions, to prevent adding new ones
+        // Freeze definitions once we start iterating on them, to prevent adding new ones
         // while iterating. If some query needs to add definitions, it should be `ensure`d above.
-        let definitions = self.untracked.definitions.leak();
-        definitions.def_path_hash_to_def_index_map()
+        self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
     }
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     #[inline]
-    pub fn cstore_untracked(self) -> MappedReadGuard<'tcx, CrateStoreDyn> {
-        ReadGuard::map(self.untracked.cstore.read(), |c| &**c)
+    pub fn cstore_untracked(self) -> FreezeReadGuard<'tcx, CrateStoreDyn> {
+        FreezeReadGuard::map(self.untracked.cstore.read(), |c| &**c)
     }
 
     /// Give out access to the untracked data without any sanity checks.
@@ -1006,7 +1004,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     #[inline]
-    pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> {
+    pub fn definitions_untracked(self) -> FreezeReadGuard<'tcx, Definitions> {
         self.untracked.definitions.read()
     }
 
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index bbd4a623330..3cafd9a8da9 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -324,7 +324,9 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
                     InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
-                    InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
+                    InferConst::Var(_) | InferConst::EffectVar(_) => {
+                        self.add_flags(TypeFlags::HAS_CT_INFER)
+                    }
                 }
             }
             ty::ConstKind::Bound(debruijn, _) => {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 97dab5cb47e..153b24acba1 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -440,7 +440,7 @@ impl<'tcx> GenericArgs<'tcx> {
         target_args: GenericArgsRef<'tcx>,
     ) -> GenericArgsRef<'tcx> {
         let defs = tcx.generics_of(source_ancestor);
-        tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.params.len())))
+        tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count())))
     }
 
     pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> {
@@ -450,6 +450,11 @@ impl<'tcx> GenericArgs<'tcx> {
     pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> {
         self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
     }
+
+    pub fn print_as_list(&self) -> String {
+        let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>();
+        format!("[{}]", v.join(", "))
+    }
 }
 
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 70a35f137d8..ceac21cf6ea 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -12,7 +12,7 @@ use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamT
 pub enum GenericParamDefKind {
     Lifetime,
     Type { has_default: bool, synthetic: bool },
-    Const { has_default: bool },
+    Const { has_default: bool, is_host_effect: bool },
 }
 
 impl GenericParamDefKind {
@@ -87,7 +87,7 @@ impl GenericParamDef {
             GenericParamDefKind::Type { has_default, .. } if has_default => {
                 Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
             }
-            GenericParamDefKind::Const { has_default } if has_default => {
+            GenericParamDefKind::Const { has_default, .. } if has_default => {
                 Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
@@ -187,7 +187,7 @@ impl<'tcx> Generics {
                 GenericParamDefKind::Type { has_default, .. } => {
                     own_defaults.types += has_default as usize;
                 }
-                GenericParamDefKind::Const { has_default } => {
+                GenericParamDefKind::Const { has_default, .. } => {
                     own_defaults.consts += has_default as usize;
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1fdc4f7500f..99b697d0ea5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -98,9 +98,9 @@ pub use self::sty::BoundRegionKind::*;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
     BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
-    EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
-    FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs, InlineConstArgsParts,
-    ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
+    EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
+    FnSig, FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs,
+    InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
     PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
     TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
 };
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ac0c88468fa..f24ac79323f 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -760,9 +760,12 @@ pub trait PrettyPrinter<'tcx>:
                 // only affect certain debug messages (e.g. messages printed
                 // from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
                 // and should have no effect on any compiler output.
+                // [Unless `-Zverbose` is used, e.g. in the output of
+                // `tests/ui/nll/ty-outlives/impl-trait-captures.rs`, for
+                // example.]
                 if self.should_print_verbose() {
                     // FIXME(eddyb) print this with `print_def_path`.
-                    p!(write("Opaque({:?}, {:?})", def_id, args));
+                    p!(write("Opaque({:?}, {})", def_id, args.print_as_list()));
                     return Ok(self);
                 }
 
@@ -894,7 +897,7 @@ pub trait PrettyPrinter<'tcx>:
                     p!(print_def_path(did, args));
                     if !args.as_closure().is_valid() {
                         p!(" closure_args=(unavailable)");
-                        p!(write(" args={:?}", args));
+                        p!(write(" args={}", args.print_as_list()));
                     } else {
                         p!(" closure_kind_ty=", print(args.as_closure().kind_ty()));
                         p!(
@@ -1123,6 +1126,17 @@ pub trait PrettyPrinter<'tcx>:
             }
         }
 
+        if self.tcx().features().return_type_notation
+            && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id)
+            && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
+            && alias_ty.def_id == def_id
+        {
+            let num_args = self.tcx().generics_of(fn_def_id).count();
+            write!(self, " {{ ")?;
+            self = self.print_def_path(fn_def_id, &args[..num_args])?;
+            write!(self, "() }}")?;
+        }
+
         Ok(self)
     }
 
@@ -1239,21 +1253,18 @@ pub trait PrettyPrinter<'tcx>:
                         .generics_of(principal.def_id)
                         .own_args_no_defaults(cx.tcx(), principal.args);
 
-                    let mut projections = predicates.projection_bounds();
-
-                    let mut args = args.iter().cloned();
-                    let arg0 = args.next();
-                    let projection0 = projections.next();
-                    if arg0.is_some() || projection0.is_some() {
-                        let args = arg0.into_iter().chain(args);
-                        let projections = projection0.into_iter().chain(projections);
+                    let mut projections: Vec<_> = predicates.projection_bounds().collect();
+                    projections.sort_by_cached_key(|proj| {
+                        cx.tcx().item_name(proj.item_def_id()).to_string()
+                    });
 
+                    if !args.is_empty() || !projections.is_empty() {
                         p!(generic_delimiters(|mut cx| {
-                            cx = cx.comma_sep(args)?;
-                            if arg0.is_some() && projection0.is_some() {
+                            cx = cx.comma_sep(args.iter().copied())?;
+                            if !args.is_empty() && !projections.is_empty() {
                                 write!(cx, ", ")?;
                             }
-                            cx.comma_sep(projections)
+                            cx.comma_sep(projections.iter().copied())
                         }));
                     }
                 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f979ddd00fa..99a19f01b2b 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -138,6 +138,12 @@ impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
     }
 }
 
+impl fmt::Debug for ty::EffectVid<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "?{}e", self.index)
+    }
+}
+
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@@ -154,7 +160,7 @@ impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
 }
 impl<'tcx> fmt::Debug for Ty<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        with_no_trimmed_paths!(fmt::Display::fmt(self, f))
+        with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
     }
 }
 
@@ -253,6 +259,7 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             InferConst::Var(var) => write!(f, "{var:?}"),
+            InferConst::EffectVar(var) => write!(f, "{var:?}"),
             InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
         }
     }
@@ -267,6 +274,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
                 Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
+                EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
                 Fresh(_) => {
                     unreachable!()
                 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 0291cdd6c57..2502e303f7a 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1577,6 +1577,20 @@ pub struct ConstVid<'tcx> {
     pub phantom: PhantomData<&'tcx ()>,
 }
 
+/// An **effect** **v**ariable **ID**.
+///
+/// Handling effect infer variables happens separately from const infer variables
+/// because we do not want to reuse any of the const infer machinery. If we try to
+/// relate an effect variable with a normal one, we would ICE, which can catch bugs
+/// where we are not correctly using the effect var for an effect param. Fallback
+/// is also implemented on top of having separate effect and normal const variables.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable)]
+pub struct EffectVid<'tcx> {
+    pub index: u32,
+    pub phantom: PhantomData<&'tcx ()>,
+}
+
 rustc_index::newtype_index! {
     /// A **region** (lifetime) **v**ariable **ID**.
     #[derive(HashStable)]
@@ -2735,6 +2749,8 @@ impl<'tcx> Ty<'tcx> {
             | ty::Error(_)
             // Extern types have metadata = ().
             | ty::Foreign(..)
+            // `dyn*` has no metadata
+            | ty::Dynamic(_, _, DynKind::DynStar)
             // If returned by `struct_tail_without_normalization` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
@@ -2743,7 +2759,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Tuple(..) => (tcx.types.unit, false),
 
             ty::Str | ty::Slice(_) => (tcx.types.usize, false),
-            ty::Dynamic(..) => {
+            ty::Dynamic(_, _, DynKind::Dyn) => {
                 let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
                 (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
             },
@@ -2857,7 +2873,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Uint(..)
             | ty::Float(..) => true,
 
-            // The voldemort ZSTs are fine.
+            // ZST which can't be named are fine.
             ty::FnDef(..) => true,
 
             ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6e55e7915c9..bf9b244936f 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -90,6 +90,10 @@ pub struct TraitImpls {
 }
 
 impl TraitImpls {
+    pub fn is_empty(&self) -> bool {
+        self.blanket_impls.is_empty() && self.non_blanket_impls.is_empty()
+    }
+
     pub fn blanket_impls(&self) -> &[DefId] {
         self.blanket_impls.as_slice()
     }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 327cd0a5d7b..7ecc7e6014d 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -722,3 +722,14 @@ pub enum UserType<'tcx> {
     /// given substitutions applied.
     TypeOf(DefId, UserArgs<'tcx>),
 }
+
+impl<'tcx> std::fmt::Display for UserType<'tcx> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Ty(arg0) => {
+                ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0))
+            }
+            Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1),
+        }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index f83c62fd580..e2ab2cb90c7 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -241,6 +241,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             let dbginfo = VarDebugInfo {
                 name,
                 source_info: SourceInfo { span, scope: self.source_scope },
+                composite: None,
                 argument_index: None,
                 value,
             };
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 5ec216cea61..7e81c8b50c2 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2287,6 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             name,
             source_info: debug_source_info,
             value: VarDebugInfoContents::Place(for_arm_body.into()),
+            composite: None,
             argument_index: None,
         });
         let locals = if has_guard.0 {
@@ -2306,6 +2307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 name,
                 source_info: debug_source_info,
                 value: VarDebugInfoContents::Place(ref_for_guard.into()),
+                composite: None,
                 argument_index: None,
             });
             LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index e614046e83e..4e10916ad61 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -823,6 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     name,
                     source_info: SourceInfo::outermost(captured_place.var_ident.span),
                     value: VarDebugInfoContents::Place(use_place),
+                    composite: None,
                     argument_index: None,
                 });
 
@@ -852,6 +853,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     name,
                     source_info,
                     value: VarDebugInfoContents::Place(arg_local.into()),
+                    composite: None,
                     argument_index: Some(argument_index as u16 + 1),
                 });
             }
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 6872ef5e985..299bf692307 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -581,6 +581,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
         }
     }
 
+    /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
+    pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V {
+        match map.find_len(place) {
+            Some(place) => self.get_idx(place, map),
+            None => V::TOP,
+        }
+    }
+
     /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
     pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
         match &self.0 {
@@ -626,45 +634,36 @@ pub struct Map {
 }
 
 impl Map {
-    fn new() -> Self {
-        Self {
+    /// Returns a map that only tracks places whose type has scalar layout.
+    ///
+    /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
+    /// chosen is an implementation detail and may not be relied upon (other than that their type
+    /// are scalars).
+    pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self {
+        let mut map = Self {
             locals: IndexVec::new(),
             projections: FxHashMap::default(),
             places: IndexVec::new(),
             value_count: 0,
             inner_values: IndexVec::new(),
             inner_values_buffer: Vec::new(),
-        }
-    }
-
-    /// Returns a map that only tracks places whose type passes the filter.
-    ///
-    /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
-    /// chosen is an implementation detail and may not be relied upon (other than that their type
-    /// passes the filter).
-    pub fn from_filter<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
-        filter: impl Fn(Ty<'tcx>) -> bool,
-        value_limit: Option<usize>,
-    ) -> Self {
-        let mut map = Self::new();
+        };
         let exclude = excluded_locals(body);
-        map.register_with_filter(tcx, body, filter, exclude, value_limit);
+        map.register(tcx, body, exclude, value_limit);
         debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len());
         map
     }
 
-    /// Register all non-excluded places that pass the filter.
-    fn register_with_filter<'tcx>(
+    /// Register all non-excluded places that have scalar layout.
+    fn register<'tcx>(
         &mut self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
-        filter: impl Fn(Ty<'tcx>) -> bool,
         exclude: BitSet<Local>,
         value_limit: Option<usize>,
     ) {
         let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len()));
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
 
         // Start by constructing the places for each bare local.
         self.locals = IndexVec::from_elem(None, &body.local_decls);
@@ -679,7 +678,7 @@ impl Map {
             self.locals[local] = Some(place);
 
             // And push the eventual children places to the worklist.
-            self.register_children(tcx, place, decl.ty, &filter, &mut worklist);
+            self.register_children(tcx, param_env, place, decl.ty, &mut worklist);
         }
 
         // `place.elem1.elem2` with type `ty`.
@@ -702,7 +701,7 @@ impl Map {
             }
 
             // And push the eventual children places to the worklist.
-            self.register_children(tcx, place, ty, &filter, &mut worklist);
+            self.register_children(tcx, param_env, place, ty, &mut worklist);
         }
 
         // Pre-compute the tree of ValueIndex nested in each PlaceIndex.
@@ -732,42 +731,52 @@ impl Map {
     fn register_children<'tcx>(
         &mut self,
         tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         place: PlaceIndex,
         ty: Ty<'tcx>,
-        filter: &impl Fn(Ty<'tcx>) -> bool,
         worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>,
     ) {
         // Allocate a value slot if it doesn't have one, and the user requested one.
-        if self.places[place].value_index.is_none() && filter(ty) {
+        assert!(self.places[place].value_index.is_none());
+        if tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.abi.is_scalar()) {
             self.places[place].value_index = Some(self.value_count.into());
             self.value_count += 1;
         }
 
         // For enums, directly create the `Discriminant`, as that's their main use.
         if ty.is_enum() {
-            let discr_ty = ty.discriminant_ty(tcx);
-            if filter(discr_ty) {
-                let discr = *self
-                    .projections
-                    .entry((place, TrackElem::Discriminant))
-                    .or_insert_with(|| {
-                        // Prepend new child to the linked list.
-                        let next = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant)));
-                        self.places[next].next_sibling = self.places[place].first_child;
-                        self.places[place].first_child = Some(next);
-                        next
-                    });
-
-                // Allocate a value slot if it doesn't have one.
-                if self.places[discr].value_index.is_none() {
-                    self.places[discr].value_index = Some(self.value_count.into());
-                    self.value_count += 1;
-                }
-            }
+            // Prepend new child to the linked list.
+            let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant)));
+            self.places[discr].next_sibling = self.places[place].first_child;
+            self.places[place].first_child = Some(discr);
+            let old = self.projections.insert((place, TrackElem::Discriminant), discr);
+            assert!(old.is_none());
+
+            // Allocate a value slot since it doesn't have one.
+            assert!(self.places[discr].value_index.is_none());
+            self.places[discr].value_index = Some(self.value_count.into());
+            self.value_count += 1;
+        }
+
+        if let Some(ref_ty) = ty.builtin_deref(true) && let ty::Slice(..) = ref_ty.ty.kind() {
+            assert!(self.places[place].value_index.is_none(), "slices are not scalars");
+
+            // Prepend new child to the linked list.
+            let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen)));
+            self.places[len].next_sibling = self.places[place].first_child;
+            self.places[place].first_child = Some(len);
+
+            let old = self.projections.insert((place, TrackElem::DerefLen), len);
+            assert!(old.is_none());
+
+            // Allocate a value slot since it doesn't have one.
+            assert!( self.places[len].value_index.is_none() );
+            self.places[len].value_index = Some(self.value_count.into());
+            self.value_count += 1;
         }
 
         // Recurse with all fields of this place.
-        iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
+        iter_fields(ty, tcx, param_env, |variant, field, ty| {
             worklist.push_back((
                 place,
                 variant.map(TrackElem::Variant),
@@ -834,6 +843,11 @@ impl Map {
         self.find_extra(place, [TrackElem::Discriminant])
     }
 
+    /// Locates the given place and applies `DerefLen`, if it exists in the tree.
+    pub fn find_len(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
+        self.find_extra(place, [TrackElem::DerefLen])
+    }
+
     /// Iterate over all direct children.
     pub fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ {
         Children::new(self, parent)
@@ -985,6 +999,8 @@ pub enum TrackElem {
     Field(FieldIdx),
     Variant(VariantIdx),
     Discriminant,
+    // Length of a slice.
+    DerefLen,
 }
 
 impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
@@ -1124,6 +1140,9 @@ fn debug_with_context_rec<V: Debug + Eq>(
                     format!("{}.{}", place_str, field.index())
                 }
             }
+            TrackElem::DerefLen => {
+                format!("Len(*{})", place_str)
+            }
         };
         debug_with_context_rec(child, &child_place_str, new, old, map, f)?;
     }
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index 2598eb2ed09..5a99afc45b0 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -42,8 +42,6 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in
     }
     .not_inherited = items do not inherit unsafety from separate enclosing items
 
-mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
-
 mir_transform_target_feature_call_label = call to function with `#[target_feature]`
 mir_transform_target_feature_call_note = can only be called if the required target features are available
 
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 0fce9cb19a8..d5af321d726 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -483,7 +483,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu
     // `mir_built` force this.
     let body = &tcx.mir_built(def).borrow();
 
-    if body.is_custom_mir() {
+    if body.is_custom_mir() || body.tainted_by_errors.is_some() {
         return tcx.arena.alloc(UnsafetyCheckResult {
             violations: Vec::new(),
             used_unsafe_blocks: Default::default(),
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 4b51beed095..b52827a1e88 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -39,6 +39,10 @@ pub struct ConstProp;
 
 impl<'tcx> MirLint<'tcx> for ConstProp {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        if body.tainted_by_errors.is_some() {
+            return;
+        }
+
         // will be evaluated by miri and produce its errors there
         if body.source.promoted.is_some() {
             return;
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index aa205655f9d..56365c5d474 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,5 +1,6 @@
 use super::*;
 
+use rustc_data_structures::captures::Captures;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{self, Body, Coverage, CoverageInfo};
 use rustc_middle::query::Providers;
@@ -12,15 +13,10 @@ pub(crate) fn provide(providers: &mut Providers) {
     providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
 }
 
-/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
-/// other words, the number of counter value references injected into the MIR (plus 1 for the
-/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected
-/// counters have a counter ID from `1..num_counters-1`.
-///
-/// `num_expressions` is the number of counter expressions added to the MIR body.
-///
-/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend
-/// code generate, to lookup counters and expressions by simple u32 indexes.
+/// Coverage codegen needs to know the total number of counter IDs and expression IDs that have
+/// been used by a function's coverage mappings. These totals are used to create vectors to hold
+/// the relevant counter and expression data, and the maximum counter ID (+ 1) is also needed by
+/// the `llvm.instrprof.increment` intrinsic.
 ///
 /// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code
 /// including injected counters. (It is OK if some counters are optimized out, but those counters
@@ -28,71 +24,51 @@ pub(crate) fn provide(providers: &mut Providers) {
 /// calls may not work; but computing the number of counters or expressions by adding `1` to the
 /// highest ID (for a given instrumented function) is valid.
 ///
-/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum
-/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a
-/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression
-/// IDs referenced by expression operands, if not already seen.
-///
-/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage`
-/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future
-/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to
-/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs.
+/// It's possible for a coverage expression to remain in MIR while one or both of its operands
+/// have been optimized away. To avoid problems in codegen, we include those operands' IDs when
+/// determining the maximum counter/expression ID, even if the underlying counter/expression is
+/// no longer present.
 struct CoverageVisitor {
-    info: CoverageInfo,
-    add_missing_operands: bool,
+    max_counter_id: CounterId,
+    max_expression_id: ExpressionId,
 }
 
 impl CoverageVisitor {
-    /// Updates `num_counters` to the maximum encountered counter ID plus 1.
+    /// Updates `max_counter_id` to the maximum encountered counter ID.
     #[inline(always)]
-    fn update_num_counters(&mut self, counter_id: CounterId) {
-        let counter_id = counter_id.as_u32();
-        self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
+    fn update_max_counter_id(&mut self, counter_id: CounterId) {
+        self.max_counter_id = self.max_counter_id.max(counter_id);
     }
 
-    /// Updates `num_expressions` to the maximum encountered expression ID plus 1.
+    /// Updates `max_expression_id` to the maximum encountered expression ID.
     #[inline(always)]
-    fn update_num_expressions(&mut self, expression_id: ExpressionId) {
-        let expression_id = expression_id.as_u32();
-        self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1);
+    fn update_max_expression_id(&mut self, expression_id: ExpressionId) {
+        self.max_expression_id = self.max_expression_id.max(expression_id);
     }
 
     fn update_from_expression_operand(&mut self, operand: Operand) {
         match operand {
-            Operand::Counter(id) => self.update_num_counters(id),
-            Operand::Expression(id) => self.update_num_expressions(id),
+            Operand::Counter(id) => self.update_max_counter_id(id),
+            Operand::Expression(id) => self.update_max_expression_id(id),
             Operand::Zero => {}
         }
     }
 
     fn visit_body(&mut self, body: &Body<'_>) {
-        for bb_data in body.basic_blocks.iter() {
-            for statement in bb_data.statements.iter() {
-                if let StatementKind::Coverage(box ref coverage) = statement.kind {
-                    if is_inlined(body, statement) {
-                        continue;
-                    }
-                    self.visit_coverage(coverage);
-                }
-            }
+        for coverage in all_coverage_in_mir_body(body) {
+            self.visit_coverage(coverage);
         }
     }
 
     fn visit_coverage(&mut self, coverage: &Coverage) {
-        if self.add_missing_operands {
-            match coverage.kind {
-                CoverageKind::Expression { lhs, rhs, .. } => {
-                    self.update_from_expression_operand(lhs);
-                    self.update_from_expression_operand(rhs);
-                }
-                _ => {}
-            }
-        } else {
-            match coverage.kind {
-                CoverageKind::Counter { id, .. } => self.update_num_counters(id),
-                CoverageKind::Expression { id, .. } => self.update_num_expressions(id),
-                _ => {}
+        match coverage.kind {
+            CoverageKind::Counter { id, .. } => self.update_max_counter_id(id),
+            CoverageKind::Expression { id, lhs, rhs, .. } => {
+                self.update_max_expression_id(id);
+                self.update_from_expression_operand(lhs);
+                self.update_from_expression_operand(rhs);
             }
+            CoverageKind::Unreachable => {}
         }
     }
 }
@@ -101,37 +77,40 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
     let mir_body = tcx.instance_mir(instance_def);
 
     let mut coverage_visitor = CoverageVisitor {
-        info: CoverageInfo { num_counters: 0, num_expressions: 0 },
-        add_missing_operands: false,
+        max_counter_id: CounterId::START,
+        max_expression_id: ExpressionId::START,
     };
 
     coverage_visitor.visit_body(mir_body);
 
-    coverage_visitor.add_missing_operands = true;
-    coverage_visitor.visit_body(mir_body);
-
-    coverage_visitor.info
+    // Add 1 to the highest IDs to get the total number of IDs.
+    CoverageInfo {
+        num_counters: (coverage_visitor.max_counter_id + 1).as_u32(),
+        num_expressions: (coverage_visitor.max_expression_id + 1).as_u32(),
+    }
 }
 
 fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> {
     let body = mir_body(tcx, def_id);
-    body.basic_blocks
-        .iter()
-        .flat_map(|data| {
-            data.statements.iter().filter_map(|statement| match statement.kind {
-                StatementKind::Coverage(box ref coverage) => {
-                    if is_inlined(body, statement) {
-                        None
-                    } else {
-                        coverage.code_region.as_ref() // may be None
-                    }
-                }
-                _ => None,
-            })
-        })
+    all_coverage_in_mir_body(body)
+        // Not all coverage statements have an attached code region.
+        .filter_map(|coverage| coverage.code_region.as_ref())
         .collect()
 }
 
+fn all_coverage_in_mir_body<'a, 'tcx>(
+    body: &'a Body<'tcx>,
+) -> impl Iterator<Item = &'a Coverage> + Captures<'tcx> {
+    body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| {
+        match statement.kind {
+            StatementKind::Coverage(box ref coverage) if !is_inlined(body, statement) => {
+                Some(coverage)
+            }
+            _ => None,
+        }
+    })
+}
+
 fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
     let scope_data = &body.source_scopes[statement.source_info.scope];
     scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some()
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index d4c9163b571..333a14be996 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -6,10 +6,10 @@ use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
-use rustc_middle::mir::visit::{MutVisitor, Visitor};
+use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
     Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
 };
@@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
         let place_limit = if tcx.sess.mir_opt_level() < 4 { Some(PLACE_LIMIT) } else { None };
 
         // Decide which places to track during the analysis.
-        let map = Map::from_filter(tcx, body, Ty::is_scalar, place_limit);
+        let map = Map::new(tcx, body, place_limit);
 
         // Perform the actual dataflow analysis.
         let analysis = ConstAnalysis::new(tcx, body, map);
@@ -58,9 +58,13 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
             .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
 
         // Collect results and patch the body afterwards.
-        let mut visitor = CollectAndPatch::new(tcx);
+        let mut visitor = CollectAndPatch::new(tcx, &body.local_decls);
         debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
-        debug_span!("patch").in_scope(|| visitor.visit_body(body));
+        debug_span!("patch").in_scope(|| {
+            for (block, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
+                visitor.visit_basic_block_data(block, bbdata);
+            }
+        })
     }
 }
 
@@ -73,7 +77,7 @@ struct ConstAnalysis<'a, 'tcx> {
 }
 
 impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
-    type Value = FlatSet<ScalarTy<'tcx>>;
+    type Value = FlatSet<ScalarInt>;
 
     const NAME: &'static str = "ConstAnalysis";
 
@@ -172,9 +176,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     if let Some(overflow_target) = overflow_target {
                         let overflow = match overflow {
                             FlatSet::Top => FlatSet::Top,
-                            FlatSet::Elem(overflow) => {
-                                self.wrap_scalar(Scalar::from_bool(overflow), self.tcx.types.bool)
-                            }
+                            FlatSet::Elem(overflow) => FlatSet::Elem(overflow.into()),
                             FlatSet::Bottom => FlatSet::Bottom,
                         };
                         // We have flooded `target` earlier.
@@ -182,6 +184,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     }
                 }
             }
+            Rvalue::Cast(
+                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize),
+                operand,
+                _,
+            ) => {
+                let pointer = self.handle_operand(operand, state);
+                state.assign(target.as_ref(), pointer, self.map());
+
+                if let Some(target_len) = self.map().find_len(target.as_ref())
+                    && let operand_ty = operand.ty(self.local_decls, self.tcx)
+                    && let Some(operand_ty) = operand_ty.builtin_deref(true)
+                    && let ty::Array(_, len) = operand_ty.ty.kind()
+                    && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int()
+                {
+                    state.insert_value_idx(target_len, FlatSet::Elem(len), self.map());
+                }
+            }
             _ => self.super_assign(target, rvalue, state),
         }
     }
@@ -191,47 +210,77 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         rvalue: &Rvalue<'tcx>,
         state: &mut State<Self::Value>,
     ) -> ValueOrPlace<Self::Value> {
-        match rvalue {
-            Rvalue::Cast(
-                kind @ (CastKind::IntToInt
-                | CastKind::FloatToInt
-                | CastKind::FloatToFloat
-                | CastKind::IntToFloat),
-                operand,
-                ty,
-            ) => match self.eval_operand(operand, state) {
-                FlatSet::Elem(op) => match kind {
-                    CastKind::IntToInt | CastKind::IntToFloat => {
-                        self.ecx.int_to_int_or_float(&op, *ty)
-                    }
-                    CastKind::FloatToInt | CastKind::FloatToFloat => {
-                        self.ecx.float_to_float_or_int(&op, *ty)
-                    }
-                    _ => unreachable!(),
+        let val = match rvalue {
+            Rvalue::Len(place) => {
+                let place_ty = place.ty(self.local_decls, self.tcx);
+                if let ty::Array(_, len) = place_ty.ty.kind() {
+                    ConstantKind::Ty(*len)
+                        .eval(self.tcx, self.param_env)
+                        .try_to_scalar_int()
+                        .map_or(FlatSet::Top, FlatSet::Elem)
+                } else if let [ProjectionElem::Deref] = place.projection[..] {
+                    state.get_len(place.local.into(), self.map())
+                } else {
+                    FlatSet::Top
                 }
-                .map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty)))
-                .unwrap_or(ValueOrPlace::TOP),
-                _ => ValueOrPlace::TOP,
-            },
+            }
+            Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self
+                        .ecx
+                        .int_to_int_or_float(&op, *ty)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
+                }
+            }
+            Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self
+                        .ecx
+                        .float_to_float_or_int(&op, *ty)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
+                }
+            }
+            Rvalue::Cast(CastKind::Transmute, operand, _) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self.wrap_immediate(*op),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
+                }
+            }
             Rvalue::BinaryOp(op, box (left, right)) => {
                 // Overflows must be ignored here.
                 let (val, _overflow) = self.binary_op(state, *op, left, right);
-                ValueOrPlace::Value(val)
+                val
             }
             Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
-                FlatSet::Elem(value) => self
-                    .ecx
-                    .unary_op(*op, &value)
-                    .map(|val| ValueOrPlace::Value(self.wrap_immty(val)))
-                    .unwrap_or(ValueOrPlace::Value(FlatSet::Top)),
-                FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom),
-                FlatSet::Top => ValueOrPlace::Value(FlatSet::Top),
+                FlatSet::Elem(value) => {
+                    self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val))
+                }
+                FlatSet::Bottom => FlatSet::Bottom,
+                FlatSet::Top => FlatSet::Top,
             },
-            Rvalue::Discriminant(place) => {
-                ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map()))
+            Rvalue::NullaryOp(null_op, ty) => {
+                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                    return ValueOrPlace::Value(FlatSet::Top);
+                };
+                let val = match null_op {
+                    NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
+                    NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
+                    NullOp::OffsetOf(fields) => layout
+                        .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index()))
+                        .bytes(),
+                    _ => return ValueOrPlace::Value(FlatSet::Top),
+                };
+                ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
             }
-            _ => self.super_rvalue(rvalue, state),
-        }
+            Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
+            _ => return self.super_rvalue(rvalue, state),
+        };
+        ValueOrPlace::Value(val)
     }
 
     fn handle_constant(
@@ -242,9 +291,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         constant
             .literal
             .eval(self.tcx, self.param_env)
-            .try_to_scalar()
-            .map(|value| FlatSet::Elem(ScalarTy(value, constant.ty())))
-            .unwrap_or(FlatSet::Top)
+            .try_to_scalar_int()
+            .map_or(FlatSet::Top, FlatSet::Elem)
     }
 
     fn handle_switch_int<'mir>(
@@ -261,9 +309,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             // We are branching on uninitialized data, this is UB, treat it as unreachable.
             // This allows the set of visited edges to grow monotonically with the lattice.
             FlatSet::Bottom => TerminatorEdges::None,
-            FlatSet::Elem(ScalarTy(scalar, _)) => {
-                let int = scalar.assert_int();
-                let choice = int.assert_bits(int.size());
+            FlatSet::Elem(scalar) => {
+                let choice = scalar.assert_bits(scalar.size());
                 TerminatorEdges::Single(targets.target_for_value(choice))
             }
             FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets },
@@ -271,16 +318,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq)]
-struct ScalarTy<'tcx>(Scalar, Ty<'tcx>);
-
-impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        // This is used for dataflow visualization, so we return something more concise.
-        std::fmt::Display::fmt(&ConstantKind::Val(ConstValue::Scalar(self.0), self.1), f)
-    }
-}
-
 impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self {
         let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
@@ -295,32 +332,62 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
 
     fn binary_op(
         &self,
-        state: &mut State<FlatSet<ScalarTy<'tcx>>>,
+        state: &mut State<FlatSet<ScalarInt>>,
         op: BinOp,
         left: &Operand<'tcx>,
         right: &Operand<'tcx>,
-    ) -> (FlatSet<ScalarTy<'tcx>>, FlatSet<bool>) {
+    ) -> (FlatSet<ScalarInt>, FlatSet<bool>) {
         let left = self.eval_operand(left, state);
         let right = self.eval_operand(right, state);
+
         match (left, right) {
+            (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
+            // Both sides are known, do the actual computation.
             (FlatSet::Elem(left), FlatSet::Elem(right)) => {
                 match self.ecx.overflowing_binary_op(op, &left, &right) {
-                    Ok((val, overflow, ty)) => (self.wrap_scalar(val, ty), FlatSet::Elem(overflow)),
+                    Ok((Scalar::Int(val), overflow, _)) => {
+                        (FlatSet::Elem(val), FlatSet::Elem(overflow))
+                    }
                     _ => (FlatSet::Top, FlatSet::Top),
                 }
             }
-            (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
-            (_, _) => {
-                // Could attempt some algebraic simplifications here.
-                (FlatSet::Top, FlatSet::Top)
+            // Exactly one side is known, attempt some algebraic simplifications.
+            (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => {
+                let layout = const_arg.layout;
+                if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) {
+                    return (FlatSet::Top, FlatSet::Top);
+                }
+
+                let arg_scalar = const_arg.to_scalar();
+                let Ok(arg_scalar) = arg_scalar.try_to_int() else {
+                    return (FlatSet::Top, FlatSet::Top);
+                };
+                let Ok(arg_value) = arg_scalar.to_bits(layout.size) else {
+                    return (FlatSet::Top, FlatSet::Top);
+                };
+
+                match op {
+                    BinOp::BitAnd if arg_value == 0 => (FlatSet::Elem(arg_scalar), FlatSet::Bottom),
+                    BinOp::BitOr
+                        if arg_value == layout.size.truncate(u128::MAX)
+                            || (layout.ty.is_bool() && arg_value == 1) =>
+                    {
+                        (FlatSet::Elem(arg_scalar), FlatSet::Bottom)
+                    }
+                    BinOp::Mul if layout.ty.is_integral() && arg_value == 0 => {
+                        (FlatSet::Elem(arg_scalar), FlatSet::Elem(false))
+                    }
+                    _ => (FlatSet::Top, FlatSet::Top),
+                }
             }
+            (FlatSet::Top, FlatSet::Top) => (FlatSet::Top, FlatSet::Top),
         }
     }
 
     fn eval_operand(
         &self,
         op: &Operand<'tcx>,
-        state: &mut State<FlatSet<ScalarTy<'tcx>>>,
+        state: &mut State<FlatSet<ScalarInt>>,
     ) -> FlatSet<ImmTy<'tcx>> {
         let value = match self.handle_operand(op, state) {
             ValueOrPlace::Value(value) => value,
@@ -328,76 +395,76 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         };
         match value {
             FlatSet::Top => FlatSet::Top,
-            FlatSet::Elem(ScalarTy(scalar, ty)) => self
-                .tcx
-                .layout_of(self.param_env.and(ty))
-                .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar, layout)))
-                .unwrap_or(FlatSet::Top),
+            FlatSet::Elem(scalar) => {
+                let ty = op.ty(self.local_decls, self.tcx);
+                self.tcx
+                    .layout_of(self.param_env.and(ty))
+                    .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout)))
+                    .unwrap_or(FlatSet::Top)
+            }
             FlatSet::Bottom => FlatSet::Bottom,
         }
     }
 
-    fn eval_discriminant(
-        &self,
-        enum_ty: Ty<'tcx>,
-        variant_index: VariantIdx,
-    ) -> Option<ScalarTy<'tcx>> {
+    fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<ScalarInt> {
         if !enum_ty.is_enum() {
             return None;
         }
         let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
         let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
-        let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?;
-        Some(ScalarTy(discr_value, discr.ty))
-    }
-
-    fn wrap_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> FlatSet<ScalarTy<'tcx>> {
-        FlatSet::Elem(ScalarTy(scalar, ty))
+        let discr_value = ScalarInt::try_from_uint(discr.val, discr_layout.size)?;
+        Some(discr_value)
     }
 
-    fn wrap_immediate(&self, imm: Immediate, ty: Ty<'tcx>) -> FlatSet<ScalarTy<'tcx>> {
+    fn wrap_immediate(&self, imm: Immediate) -> FlatSet<ScalarInt> {
         match imm {
-            Immediate::Scalar(scalar) => self.wrap_scalar(scalar, ty),
+            Immediate::Scalar(Scalar::Int(scalar)) => FlatSet::Elem(scalar),
             _ => FlatSet::Top,
         }
     }
 
-    fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarTy<'tcx>> {
-        self.wrap_immediate(*val, val.layout.ty)
+    fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarInt> {
+        self.wrap_immediate(*val)
     }
 }
 
-struct CollectAndPatch<'tcx> {
+struct CollectAndPatch<'tcx, 'locals> {
     tcx: TyCtxt<'tcx>,
+    local_decls: &'locals LocalDecls<'tcx>,
 
     /// For a given MIR location, this stores the values of the operands used by that location. In
     /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
     /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
-    before_effect: FxHashMap<(Location, Place<'tcx>), ScalarTy<'tcx>>,
+    before_effect: FxHashMap<(Location, Place<'tcx>), ScalarInt>,
 
     /// Stores the assigned values for assignments where the Rvalue is constant.
-    assignments: FxHashMap<Location, ScalarTy<'tcx>>,
+    assignments: FxHashMap<Location, ScalarInt>,
 }
 
-impl<'tcx> CollectAndPatch<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
+impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> {
+    fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
+        Self {
+            tcx,
+            local_decls,
+            before_effect: FxHashMap::default(),
+            assignments: FxHashMap::default(),
+        }
     }
 
-    fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> {
+    fn make_operand(&self, scalar: ScalarInt, ty: Ty<'tcx>) -> Operand<'tcx> {
         Operand::Constant(Box::new(Constant {
             span: DUMMY_SP,
             user_ty: None,
-            literal: ConstantKind::Val(ConstValue::Scalar(scalar.0), scalar.1),
+            literal: ConstantKind::Val(ConstValue::Scalar(scalar.into()), ty),
         }))
     }
 }
 
 impl<'mir, 'tcx>
     ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
-    for CollectAndPatch<'tcx>
+    for CollectAndPatch<'tcx, '_>
 {
-    type FlowState = State<FlatSet<ScalarTy<'tcx>>>;
+    type FlowState = State<FlatSet<ScalarInt>>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
@@ -453,8 +520,8 @@ impl<'mir, 'tcx>
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -462,7 +529,8 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
         if let Some(value) = self.assignments.get(&location) {
             match &mut statement.kind {
                 StatementKind::Assign(box (_, rvalue)) => {
-                    *rvalue = Rvalue::Use(self.make_operand(value.clone()));
+                    let ty = rvalue.ty(self.local_decls, self.tcx);
+                    *rvalue = Rvalue::Use(self.make_operand(*value, ty));
                 }
                 _ => bug!("found assignment info for non-assign statement"),
             }
@@ -475,33 +543,56 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
         match operand {
             Operand::Copy(place) | Operand::Move(place) => {
                 if let Some(value) = self.before_effect.get(&(location, *place)) {
-                    *operand = self.make_operand(value.clone());
+                    let ty = place.ty(self.local_decls, self.tcx).ty;
+                    *operand = self.make_operand(*value, ty);
+                } else if !place.projection.is_empty() {
+                    self.super_operand(operand, location)
                 }
             }
-            _ => (),
+            Operand::Constant(_) => {}
+        }
+    }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: PlaceElem<'tcx>,
+        location: Location,
+    ) -> Option<PlaceElem<'tcx>> {
+        if let PlaceElem::Index(local) = elem
+            && let Some(value) = self.before_effect.get(&(location, local.into()))
+            && let Ok(offset) = value.try_to_target_usize(self.tcx)
+            && let Some(min_length) = offset.checked_add(1)
+        {
+            Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
+        } else {
+            None
         }
     }
 }
 
-struct OperandCollector<'tcx, 'map, 'a> {
-    state: &'a State<FlatSet<ScalarTy<'tcx>>>,
-    visitor: &'a mut CollectAndPatch<'tcx>,
+struct OperandCollector<'tcx, 'map, 'locals, 'a> {
+    state: &'a State<FlatSet<ScalarInt>>,
+    visitor: &'a mut CollectAndPatch<'tcx, 'locals>,
     map: &'map Map,
 }
 
-impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
+impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        match operand {
-            Operand::Copy(place) | Operand::Move(place) => {
-                match self.state.get(place.as_ref(), self.map) {
-                    FlatSet::Top => (),
-                    FlatSet::Elem(value) => {
-                        self.visitor.before_effect.insert((location, *place), value);
-                    }
-                    FlatSet::Bottom => (),
-                }
+        if let Some(place) = operand.place() {
+            if let FlatSet::Elem(value) = self.state.get(place.as_ref(), self.map) {
+                self.visitor.before_effect.insert((location, place), value);
+            } else if !place.projection.is_empty() {
+                // Try to propagate into `Index` projections.
+                self.super_operand(operand, location)
             }
-            _ => (),
+        }
+    }
+
+    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) {
+        if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt
+            && let FlatSet::Elem(value) = self.state.get(local.into(), self.map)
+        {
+            self.visitor.before_effect.insert((location, local.into()), value);
         }
     }
 }
@@ -572,7 +663,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         _bin_op: BinOp,
         _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
         _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
-    ) -> interpret::InterpResult<'tcx, (interpret::Scalar<Self::Provenance>, bool, Ty<'tcx>)> {
+    ) -> interpret::InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)> {
         throw_unsup!(Unsupported("".into()))
     }
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 4b796d79ef6..35373bcaa41 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -258,10 +258,3 @@ pub(crate) struct MustNotSuspendReason {
     pub span: Span,
     pub reason: String,
 }
-
-#[derive(Diagnostic)]
-#[diag(mir_transform_simd_shuffle_last_const)]
-pub(crate) struct SimdShuffleLastConst {
-    #[primary_span]
-    pub span: Span,
-}
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index a8dc91ca439..13277d62bf4 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -1,11 +1,10 @@
 //! Lowers intrinsic calls
 
-use crate::{errors, MirPass};
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
 pub struct LowerIntrinsics;
@@ -304,9 +303,6 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Unreachable;
                         }
                     }
-                    sym::simd_shuffle => {
-                        validate_simd_shuffle(tcx, args, terminator.source_info.span);
-                    }
                     _ => {}
                 }
             }
@@ -325,9 +321,3 @@ fn resolve_rust_intrinsic<'tcx>(
     }
     None
 }
-
-fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
-    if !matches!(args[2], Operand::Constant(_)) {
-        tcx.sess.emit_err(errors::SimdShuffleLastConst { span });
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 9c6c55b0811..c13bafa9fbb 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -87,11 +87,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
                     var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
                 }
             }
-            VarDebugInfoContents::Composite { ty, fragments: _ } => {
-                if self.known_to_be_zst(ty) {
-                    var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty))
-                }
-            }
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index e66ae8ff884..c21b1724cbb 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -1,4 +1,5 @@
 use crate::MirPass;
+use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_index::bit_set::{BitSet, GrowableBitSet};
 use rustc_index::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
@@ -147,7 +148,7 @@ fn escaping_locals<'tcx>(
         }
 
         // We ignore anything that happens in debuginfo, since we expand it using
-        // `VarDebugInfoContents::Composite`.
+        // `VarDebugInfoFragment`.
         fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {}
     }
 }
@@ -246,9 +247,7 @@ fn replace_flattened_locals<'tcx>(
     for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() {
         visitor.visit_user_type_annotation(index, annotation);
     }
-    for var_debug_info in &mut body.var_debug_info {
-        visitor.visit_var_debug_info(var_debug_info);
-    }
+    visitor.expand_var_debug_info(&mut body.var_debug_info);
     let ReplacementVisitor { patch, all_dead_locals, .. } = visitor;
     patch.apply(body);
     all_dead_locals
@@ -256,7 +255,7 @@ fn replace_flattened_locals<'tcx>(
 
 struct ReplacementVisitor<'tcx, 'll> {
     tcx: TyCtxt<'tcx>,
-    /// This is only used to compute the type for `VarDebugInfoContents::Composite`.
+    /// This is only used to compute the type for `VarDebugInfoFragment`.
     local_decls: &'ll LocalDecls<'tcx>,
     /// Work to do.
     replacements: &'ll ReplacementMap<'tcx>,
@@ -266,16 +265,38 @@ struct ReplacementVisitor<'tcx, 'll> {
 }
 
 impl<'tcx> ReplacementVisitor<'tcx, '_> {
-    fn gather_debug_info_fragments(&self, local: Local) -> Option<Vec<VarDebugInfoFragment<'tcx>>> {
-        let mut fragments = Vec::new();
-        let parts = self.replacements.place_fragments(local.into())?;
-        for (field, ty, replacement_local) in parts {
-            fragments.push(VarDebugInfoFragment {
-                projection: vec![PlaceElem::Field(field, ty)],
-                contents: Place::from(replacement_local),
-            });
-        }
-        Some(fragments)
+    #[instrument(level = "trace", skip(self))]
+    fn expand_var_debug_info(&mut self, var_debug_info: &mut Vec<VarDebugInfo<'tcx>>) {
+        var_debug_info.flat_map_in_place(|mut var_debug_info| {
+            let place = match var_debug_info.value {
+                VarDebugInfoContents::Const(_) => return vec![var_debug_info],
+                VarDebugInfoContents::Place(ref mut place) => place,
+            };
+
+            if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) {
+                *place = repl;
+                return vec![var_debug_info];
+            }
+
+            let Some(parts) = self.replacements.place_fragments(*place) else {
+                return vec![var_debug_info];
+            };
+
+            let ty = place.ty(self.local_decls, self.tcx).ty;
+
+            parts
+                .map(|(field, field_ty, replacement_local)| {
+                    let mut var_debug_info = var_debug_info.clone();
+                    let composite = var_debug_info.composite.get_or_insert_with(|| {
+                        Box::new(VarDebugInfoFragment { ty, projection: Vec::new() })
+                    });
+                    composite.projection.push(PlaceElem::Field(field, field_ty));
+
+                    var_debug_info.value = VarDebugInfoContents::Place(replacement_local.into());
+                    var_debug_info
+                })
+                .collect()
+        });
     }
 }
 
@@ -422,48 +443,6 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
         self.super_statement(statement, location)
     }
 
-    #[instrument(level = "trace", skip(self))]
-    fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
-        match &mut var_debug_info.value {
-            VarDebugInfoContents::Place(ref mut place) => {
-                if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) {
-                    *place = repl;
-                } else if let Some(local) = place.as_local()
-                    && let Some(fragments) = self.gather_debug_info_fragments(local)
-                {
-                    let ty = place.ty(self.local_decls, self.tcx).ty;
-                    var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments };
-                }
-            }
-            VarDebugInfoContents::Composite { ty: _, ref mut fragments } => {
-                let mut new_fragments = Vec::new();
-                debug!(?fragments);
-                fragments.retain_mut(|fragment| {
-                    if let Some(repl) =
-                            self.replacements.replace_place(self.tcx, fragment.contents.as_ref())
-                        {
-                            fragment.contents = repl;
-                            true
-                        } else if let Some(local) = fragment.contents.as_local()
-                            && let Some(frg) = self.gather_debug_info_fragments(local)
-                        {
-                            new_fragments.extend(frg.into_iter().map(|mut f| {
-                                f.projection.splice(0..0, fragment.projection.iter().copied());
-                                f
-                            }));
-                            false
-                        } else {
-                            true
-                        }
-                });
-                debug!(?fragments);
-                debug!(?new_fragments);
-                fragments.extend(new_fragments);
-            }
-            VarDebugInfoContents::Const(_) => {}
-        }
-    }
-
     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
         assert!(!self.all_dead_locals.contains(*local));
     }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 5d6c574baa6..c4e8d9006e6 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -106,7 +106,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
         let mut cursor_snapshot = self.cursor_snapshot.clone();
         let tokens =
             std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
-                .chain((0..self.num_calls).map(|_| {
+                .chain(std::iter::repeat_with(|| {
                     let token = cursor_snapshot.next();
                     (FlatToken::Token(token.0), token.1)
                 }))
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 233c7016417..aad4edaba90 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -73,12 +73,16 @@ impl<'a> Parser<'a> {
             if !self.maybe_consume_incorrect_semicolon(&items) {
                 let msg = format!("expected item, found {token_str}");
                 let mut err = self.struct_span_err(self.token.span, msg);
-                let label = if self.is_kw_followed_by_ident(kw::Let) {
-                    "consider using `const` or `static` instead of `let` for global variables"
+                let span = self.token.span;
+                if self.is_kw_followed_by_ident(kw::Let) {
+                    err.span_label(
+                        span,
+                        "consider using `const` or `static` instead of `let` for global variables",
+                    );
                 } else {
-                    "expected item"
+                    err.span_label(span, "expected item")
+                        .note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
                 };
-                err.span_label(self.token.span, label);
                 return Err(err);
             }
         }
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index 72da398d3fc..14330353239 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -5,4 +5,4 @@ edition = "2021"
 
 [dependencies]
 rustc_lexer = { path = "../rustc_lexer" }
-rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_index = { path = "../rustc_index", default-features = false }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 88452ccdf05..a6c7eb8d912 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -1011,7 +1011,7 @@ fn unescape_string(string: &str) -> Option<string::String> {
 
 // Assert a reasonable size for `Piece`
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Piece<'_>, 16);
+rustc_index::static_assert_size!(Piece<'_>, 16);
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 57598cf8bcf..9f3cd656bd1 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -4,14 +4,14 @@
 -passes_see_issue =
     see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
 
-passes_abi =
-    abi: {$abi}
-
+passes_abi_invalid_attribute =
+    `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+passes_abi_ne =
+    ABIs are not compatible
+    left ABI = {$left}
+    right ABI = {$right}
 passes_abi_of =
-    fn_abi_of_instance({$fn_name}) = {$fn_abi}
-
-passes_align =
-    align: {$align}
+    fn_abi_of({$fn_name}) = {$fn_abi}
 
 passes_allow_incoherent_impl =
     `rustc_allow_incoherent_impl` attribute should be applied to impl items.
@@ -318,9 +318,6 @@ passes_has_incoherent_inherent_impl =
     `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
     .label = only adts, extern types and traits are supported
 
-passes_homogeneous_aggregate =
-    homogeneous_aggregate: {$homogeneous_aggregate}
-
 passes_ignored_attr =
     `#[{$sym}]` is ignored on struct fields and match arms
     .warn = {-passes_previously_accepted}
@@ -404,9 +401,18 @@ passes_lang_item_on_incorrect_target =
 
 passes_layout =
     layout error: {$layout_error}
-
+passes_layout_abi =
+    abi: {$abi}
+passes_layout_align =
+    align: {$align}
+passes_layout_homogeneous_aggregate =
+    homogeneous_aggregate: {$homogeneous_aggregate}
+passes_layout_invalid_attribute =
+    `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
 passes_layout_of =
     layout_of({$normalized_ty}) = {$ty_layout}
+passes_layout_size =
+    size: {$size}
 
 passes_link =
     attribute should be applied to an `extern` block with non-Rust ABI
@@ -662,9 +668,6 @@ passes_should_be_applied_to_trait =
     attribute should be applied to a trait
     .label = not a trait
 
-passes_size =
-    size: {$size}
-
 passes_skipping_const_checks = skipping const checks
 
 passes_stability_promotable =
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index 5c0438e78ae..9e4d960af14 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -1,44 +1,66 @@
 use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::layout::{FnAbiError, LayoutError};
-use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt};
+use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
+use rustc_target::abi::call::FnAbi;
 
-use crate::errors::{AbiOf, UnrecognizedField};
+use super::layout_test::ensure_wf;
+use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField};
 
 pub fn test_abi(tcx: TyCtxt<'_>) {
     if !tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing ABI
         return;
     }
-    for id in tcx.hir().items() {
-        match tcx.def_kind(id.owner_id) {
-            DefKind::Fn => {
-                for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
-                    dump_abi_of(tcx, id.owner_id.def_id.into(), attr);
+    for id in tcx.hir_crate_items(()).definitions() {
+        for attr in tcx.get_attrs(id, sym::rustc_abi) {
+            match tcx.def_kind(id) {
+                DefKind::Fn | DefKind::AssocFn => {
+                    dump_abi_of_fn_item(tcx, id, attr);
                 }
-            }
-            DefKind::Impl { .. } => {
-                // To find associated functions we need to go into the child items here.
-                for &id in tcx.associated_item_def_ids(id.owner_id) {
-                    if matches!(tcx.def_kind(id), DefKind::AssocFn) {
-                        for attr in tcx.get_attrs(id, sym::rustc_abi) {
-                            dump_abi_of(tcx, id, attr);
-                        }
-                    }
+                DefKind::TyAlias { .. } => {
+                    dump_abi_of_fn_type(tcx, id, attr);
+                }
+                _ => {
+                    tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
                 }
             }
-            _ => {}
         }
     }
 }
 
-fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
+fn unwrap_fn_abi<'tcx>(
+    abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>,
+    tcx: TyCtxt<'tcx>,
+    item_def_id: LocalDefId,
+) -> &'tcx FnAbi<'tcx, Ty<'tcx>> {
+    match abi {
+        Ok(abi) => abi,
+        Err(FnAbiError::Layout(layout_error)) => {
+            tcx.sess.emit_fatal(Spanned {
+                node: layout_error.into_diagnostic(),
+                span: tcx.def_span(item_def_id),
+            });
+        }
+        Err(FnAbiError::AdjustForForeignAbi(e)) => {
+            // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
+            // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
+            // isn't the worst thing. Also this matches what codegen does.
+            span_bug!(
+                tcx.def_span(item_def_id),
+                "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
+            )
+        }
+    }
+}
+
+fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let args = GenericArgs::identity_for_item(tcx, item_def_id);
-    let instance = match Instance::resolve(tcx, param_env, item_def_id, args) {
+    let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) {
         Ok(Some(instance)) => instance,
         Ok(None) => {
             // Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
@@ -51,43 +73,125 @@ fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
         }
         Err(_guaranteed) => return,
     };
-    match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) {
-        Ok(abi) => {
-            // Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
-            // The `..` are the names of fields to dump.
-            let meta_items = attr.meta_item_list().unwrap_or_default();
-            for meta_item in meta_items {
-                match meta_item.name_or_empty() {
-                    sym::debug => {
-                        let fn_name = tcx.item_name(item_def_id);
-                        tcx.sess.emit_err(AbiOf {
-                            span: tcx.def_span(item_def_id),
-                            fn_name,
-                            fn_abi: format!("{:#?}", abi),
-                        });
-                    }
+    let abi = unwrap_fn_abi(
+        tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))),
+        tcx,
+        item_def_id,
+    );
 
-                    name => {
-                        tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
-                    }
-                }
+    // Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
+    // The `..` are the names of fields to dump.
+    let meta_items = attr.meta_item_list().unwrap_or_default();
+    for meta_item in meta_items {
+        match meta_item.name_or_empty() {
+            sym::debug => {
+                let fn_name = tcx.item_name(item_def_id.into());
+                tcx.sess.emit_err(AbiOf {
+                    span: tcx.def_span(item_def_id),
+                    fn_name,
+                    // FIXME: using the `Debug` impl here isn't ideal.
+                    fn_abi: format!("{:#?}", abi),
+                });
             }
-        }
 
-        Err(FnAbiError::Layout(layout_error)) => {
-            tcx.sess.emit_fatal(Spanned {
-                node: layout_error.into_diagnostic(),
-                span: tcx.def_span(item_def_id),
-            });
+            name => {
+                tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
+            }
         }
-        Err(FnAbiError::AdjustForForeignAbi(e)) => {
-            // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
-            // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
-            // isn't the worst thing. Also this matches what codegen does.
-            span_bug!(
-                tcx.def_span(item_def_id),
-                "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
-            )
+    }
+}
+
+fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, Ty<'tcx>>) -> bool {
+    if abi1.conv != abi2.conv
+        || abi1.args.len() != abi2.args.len()
+        || abi1.c_variadic != abi2.c_variadic
+        || abi1.fixed_count != abi2.fixed_count
+        || abi1.can_unwind != abi2.can_unwind
+    {
+        return false;
+    }
+
+    abi1.ret.eq_abi(&abi2.ret)
+        && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2))
+}
+
+fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
+    let param_env = tcx.param_env(item_def_id);
+    let ty = tcx.type_of(item_def_id).instantiate_identity();
+    let span = tcx.def_span(item_def_id);
+    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+        return;
+    }
+    let meta_items = attr.meta_item_list().unwrap_or_default();
+    for meta_item in meta_items {
+        match meta_item.name_or_empty() {
+            sym::debug => {
+                let ty::FnPtr(sig) = ty.kind() else {
+                    span_bug!(
+                        meta_item.span(),
+                        "`#[rustc_abi(debug)]` on a type alias requires function pointer type"
+                    );
+                };
+                let abi = unwrap_fn_abi(
+                    tcx.fn_abi_of_fn_ptr(param_env.and((*sig, /* extra_args */ ty::List::empty()))),
+                    tcx,
+                    item_def_id,
+                );
+
+                let fn_name = tcx.item_name(item_def_id.into());
+                tcx.sess.emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
+            }
+            sym::assert_eq => {
+                let ty::Tuple(fields) = ty.kind() else {
+                    span_bug!(
+                        meta_item.span(),
+                        "`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
+                    );
+                };
+                let [field1, field2] = ***fields else {
+                    span_bug!(
+                        meta_item.span(),
+                        "`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
+                    );
+                };
+                let ty::FnPtr(sig1) = field1.kind() else {
+                    span_bug!(
+                        meta_item.span(),
+                        "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
+                    );
+                };
+                let abi1 = unwrap_fn_abi(
+                    tcx.fn_abi_of_fn_ptr(
+                        param_env.and((*sig1, /* extra_args */ ty::List::empty())),
+                    ),
+                    tcx,
+                    item_def_id,
+                );
+                let ty::FnPtr(sig2) = field2.kind() else {
+                    span_bug!(
+                        meta_item.span(),
+                        "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
+                    );
+                };
+                let abi2 = unwrap_fn_abi(
+                    tcx.fn_abi_of_fn_ptr(
+                        param_env.and((*sig2, /* extra_args */ ty::List::empty())),
+                    ),
+                    tcx,
+                    item_def_id,
+                );
+
+                if !test_abi_eq(abi1, abi2) {
+                    tcx.sess.emit_err(AbiNe {
+                        span,
+                        left: format!("{:#?}", abi1),
+                        right: format!("{:#?}", abi2),
+                    });
+                }
+            }
+            name => {
+                tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
+            }
         }
     }
 }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 32dd02a4aa9..d7319ef91e0 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -873,32 +873,32 @@ pub struct DuplicateDiagnosticItemInCrate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_abi)]
-pub struct Abi {
+#[diag(passes_layout_abi)]
+pub struct LayoutAbi {
     #[primary_span]
     pub span: Span,
     pub abi: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_align)]
-pub struct Align {
+#[diag(passes_layout_align)]
+pub struct LayoutAlign {
     #[primary_span]
     pub span: Span,
     pub align: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_size)]
-pub struct Size {
+#[diag(passes_layout_size)]
+pub struct LayoutSize {
     #[primary_span]
     pub span: Span,
     pub size: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_homogeneous_aggregate)]
-pub struct HomogeneousAggregate {
+#[diag(passes_layout_homogeneous_aggregate)]
+pub struct LayoutHomogeneousAggregate {
     #[primary_span]
     pub span: Span,
     pub homogeneous_aggregate: String,
@@ -914,6 +914,13 @@ pub struct LayoutOf {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_layout_invalid_attribute)]
+pub struct LayoutInvalidAttribute {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_abi_of)]
 pub struct AbiOf {
     #[primary_span]
@@ -923,6 +930,22 @@ pub struct AbiOf {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_abi_ne)]
+pub struct AbiNe {
+    #[primary_span]
+    pub span: Span,
+    pub left: String,
+    pub right: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_abi_invalid_attribute)]
+pub struct AbiInvalidAttribute {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_unrecognized_field)]
 pub struct UnrecognizedField {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index d839fee07a6..e3a63f2e004 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -2,34 +2,76 @@ use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::{infer::TyCtxtInferExt, traits};
 
-use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
+use crate::errors::{
+    LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
+    LayoutSize, UnrecognizedField,
+};
 
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if !tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         return;
     }
-    for id in tcx.hir().items() {
-        if matches!(
-            tcx.def_kind(id.owner_id),
-            DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
-        ) {
-            for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
-                dump_layout_of(tcx, id.owner_id.def_id, attr);
+    for id in tcx.hir_crate_items(()).definitions() {
+        for attr in tcx.get_attrs(id, sym::rustc_layout) {
+            match tcx.def_kind(id) {
+                DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union => {
+                    dump_layout_of(tcx, id, attr);
+                }
+                _ => {
+                    tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) });
+                }
             }
         }
     }
 }
 
+pub fn ensure_wf<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    def_id: LocalDefId,
+    span: Span,
+) -> bool {
+    let pred = ty::ClauseKind::WellFormed(ty.into());
+    let obligation = traits::Obligation::new(
+        tcx,
+        traits::ObligationCause::new(
+            span,
+            def_id,
+            traits::ObligationCauseCode::WellFormed(Some(traits::WellFormedLoc::Ty(def_id))),
+        ),
+        param_env,
+        pred,
+    );
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = traits::ObligationCtxt::new(&infcx);
+    ocx.register_obligation(obligation);
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors);
+        false
+    } else {
+        // looks WF!
+        true
+    }
+}
+
 fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
+    let span = tcx.def_span(item_def_id.to_def_id());
+    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+        return;
+    }
     match tcx.layout_of(param_env.and(ty)) {
         Ok(ty_layout) => {
             // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
@@ -38,29 +80,24 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
             for meta_item in meta_items {
                 match meta_item.name_or_empty() {
                     sym::abi => {
-                        tcx.sess.emit_err(Abi {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            abi: format!("{:?}", ty_layout.abi),
-                        });
+                        tcx.sess.emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) });
                     }
 
                     sym::align => {
-                        tcx.sess.emit_err(Align {
-                            span: tcx.def_span(item_def_id.to_def_id()),
+                        tcx.sess.emit_err(LayoutAlign {
+                            span,
                             align: format!("{:?}", ty_layout.align),
                         });
                     }
 
                     sym::size => {
-                        tcx.sess.emit_err(Size {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            size: format!("{:?}", ty_layout.size),
-                        });
+                        tcx.sess
+                            .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
                     }
 
                     sym::homogeneous_aggregate => {
-                        tcx.sess.emit_err(HomogeneousAggregate {
-                            span: tcx.def_span(item_def_id.to_def_id()),
+                        tcx.sess.emit_err(LayoutHomogeneousAggregate {
+                            span,
                             homogeneous_aggregate: format!(
                                 "{:?}",
                                 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
@@ -70,18 +107,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
 
                     sym::debug => {
                         let normalized_ty = format!(
-                            "{:?}",
+                            "{}",
                             tcx.normalize_erasing_regions(
                                 param_env.with_reveal_all_normalized(tcx),
                                 ty,
                             )
                         );
+                        // FIXME: using the `Debug` impl here isn't ideal.
                         let ty_layout = format!("{:#?}", *ty_layout);
-                        tcx.sess.emit_err(LayoutOf {
-                            span: tcx.def_span(item_def_id.to_def_id()),
-                            normalized_ty,
-                            ty_layout,
-                        });
+                        tcx.sess.emit_err(LayoutOf { span, normalized_ty, ty_layout });
                     }
 
                     name => {
@@ -92,11 +126,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
         }
 
         Err(layout_error) => {
-            tcx.sess.emit_fatal(Spanned {
-                node: layout_error.into_diagnostic(),
-
-                span: tcx.def_span(item_def_id.to_def_id()),
-            });
+            tcx.sess.emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index e62833b358b..1239d6d91ac 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -90,6 +90,10 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
                 .typeck_results()
                 .type_dependent_def(expr.hir_id)
                 .map(|(kind, def_id)| Res::Def(kind, def_id)),
+            hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
+                self.reachable_symbols.insert(def_id);
+                None
+            }
             _ => None,
         };
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 906a36cdb25..1c2303ae9e0 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -836,7 +836,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
                         self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
                     }
                 }
-                GenericParamDefKind::Const { has_default } => {
+                GenericParamDefKind::Const { has_default, .. } => {
                     self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
                     if has_default {
                         self.visit(
@@ -1463,14 +1463,15 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
         };
 
         let vis = self.tcx.local_visibility(local_def_id);
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
         let span = self.tcx.def_span(self.item_def_id.to_def_id());
         let vis_span = self.tcx.def_span(def_id);
         if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) {
             let vis_descr = match vis {
                 ty::Visibility::Public => "public",
                 ty::Visibility::Restricted(vis_def_id) => {
-                    if vis_def_id == self.tcx.parent_module(hir_id).to_local_def_id() {
+                    if vis_def_id
+                        == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
+                    {
                         "private"
                     } else if vis_def_id.is_top_level_module() {
                         "crate-private"
@@ -1504,7 +1505,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
             };
             self.tcx.emit_spanned_lint(
                 lint,
-                hir_id,
+                self.tcx.hir().local_def_id_to_hir_id(self.item_def_id),
                 span,
                 PrivateInterfacesOrBoundsLint {
                     item_span: span,
diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs
new file mode 100644
index 00000000000..6ba3924f65e
--- /dev/null
+++ b/compiler/rustc_query_system/src/dep_graph/edges.rs
@@ -0,0 +1,73 @@
+use crate::dep_graph::DepNodeIndex;
+use smallvec::SmallVec;
+use std::hash::{Hash, Hasher};
+use std::iter::Extend;
+use std::ops::Deref;
+
+#[derive(Default, Debug)]
+pub struct EdgesVec {
+    max: u32,
+    edges: SmallVec<[DepNodeIndex; EdgesVec::INLINE_CAPACITY]>,
+}
+
+impl Hash for EdgesVec {
+    #[inline]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        Hash::hash(&self.edges, hasher)
+    }
+}
+
+impl EdgesVec {
+    pub const INLINE_CAPACITY: usize = 8;
+
+    #[inline]
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    #[inline]
+    pub fn push(&mut self, edge: DepNodeIndex) {
+        self.max = self.max.max(edge.as_u32());
+        self.edges.push(edge);
+    }
+
+    #[inline]
+    pub fn max_index(&self) -> u32 {
+        self.max
+    }
+}
+
+impl Deref for EdgesVec {
+    type Target = [DepNodeIndex];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.edges.as_slice()
+    }
+}
+
+impl FromIterator<DepNodeIndex> for EdgesVec {
+    #[inline]
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = DepNodeIndex>,
+    {
+        let mut vec = EdgesVec::new();
+        for index in iter {
+            vec.push(index)
+        }
+        vec
+    }
+}
+
+impl Extend<DepNodeIndex> for EdgesVec {
+    #[inline]
+    fn extend<T>(&mut self, iter: T)
+    where
+        T: IntoIterator<Item = DepNodeIndex>,
+    {
+        for elem in iter {
+            self.push(elem);
+        }
+    }
+}
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 0d4d13ac20d..fa54e1a2e6a 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -8,7 +8,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
 use rustc_data_structures::unord::UnordMap;
 use rustc_index::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-use smallvec::{smallvec, SmallVec};
 use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
@@ -19,6 +18,7 @@ use std::sync::atomic::Ordering::Relaxed;
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
+use crate::dep_graph::EdgesVec;
 use crate::ich::StableHashingContext;
 use crate::query::{QueryContext, QuerySideEffects};
 
@@ -137,7 +137,7 @@ impl<K: DepKind> DepGraph<K> {
         let _green_node_index = current.intern_new_node(
             profiler,
             DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
-            smallvec![],
+            EdgesVec::new(),
             Fingerprint::ZERO,
         );
         assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
@@ -147,7 +147,7 @@ impl<K: DepKind> DepGraph<K> {
             profiler,
             &prev_graph,
             DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
-            smallvec![],
+            EdgesVec::new(),
             None,
             false,
         );
@@ -356,12 +356,12 @@ impl<K: DepKind> DepGraphData<K> {
 
         let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg));
         let (result, edges) = if cx.dep_context().is_eval_always(key.kind) {
-            (with_deps(TaskDepsRef::EvalAlways), smallvec![])
+            (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new())
         } else {
             let task_deps = Lock::new(TaskDeps {
                 #[cfg(debug_assertions)]
                 node: Some(key),
-                reads: SmallVec::new(),
+                reads: EdgesVec::new(),
                 read_set: Default::default(),
                 phantom_data: PhantomData,
             });
@@ -486,14 +486,14 @@ impl<K: DepKind> DepGraph<K> {
 
                 // As long as we only have a low number of reads we can avoid doing a hash
                 // insert and potentially allocating/reallocating the hashmap
-                let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
+                let new_read = if task_deps.reads.len() < EdgesVec::INLINE_CAPACITY {
                     task_deps.reads.iter().all(|other| *other != dep_node_index)
                 } else {
                     task_deps.read_set.insert(dep_node_index)
                 };
                 if new_read {
                     task_deps.reads.push(dep_node_index);
-                    if task_deps.reads.len() == TASK_DEPS_READS_CAP {
+                    if task_deps.reads.len() == EdgesVec::INLINE_CAPACITY {
                         // Fill `read_set` with what we have so far so we can use the hashset
                         // next time
                         task_deps.read_set.extend(task_deps.reads.iter().copied());
@@ -572,7 +572,7 @@ impl<K: DepKind> DepGraph<K> {
                 }
             }
 
-            let mut edges = SmallVec::new();
+            let mut edges = EdgesVec::new();
             K::read_deps(|task_deps| match task_deps {
                 TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()),
                 TaskDepsRef::EvalAlways => {
@@ -629,12 +629,7 @@ impl<K: DepKind> DepGraphData<K> {
         if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
             self.current.prev_index_to_index.lock()[prev_index]
         } else {
-            self.current
-                .new_node_to_index
-                .get_shard_by_value(dep_node)
-                .lock()
-                .get(dep_node)
-                .copied()
+            self.current.new_node_to_index.lock_shard_by_value(dep_node).get(dep_node).copied()
         }
     }
 
@@ -872,7 +867,7 @@ impl<K: DepKind> DepGraphData<K> {
 
         let prev_deps = self.previous.edge_targets_from(prev_dep_node_index);
 
-        for &dep_dep_node_index in prev_deps {
+        for dep_dep_node_index in prev_deps {
             self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?;
         }
 
@@ -1201,8 +1196,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
         edges: EdgesVec,
         current_fingerprint: Fingerprint,
     ) -> DepNodeIndex {
-        let dep_node_index = match self.new_node_to_index.get_shard_by_value(&key).lock().entry(key)
-        {
+        let dep_node_index = match self.new_node_to_index.lock_shard_by_value(&key).entry(key) {
             Entry::Occupied(entry) => *entry.get(),
             Entry::Vacant(entry) => {
                 let dep_node_index =
@@ -1308,8 +1302,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
                 let key = prev_graph.index_to_node(prev_index);
                 let edges = prev_graph
                     .edge_targets_from(prev_index)
-                    .iter()
-                    .map(|i| prev_index_to_index[*i].unwrap())
+                    .map(|i| prev_index_to_index[i].unwrap())
                     .collect();
                 let fingerprint = prev_graph.fingerprint_by_index(prev_index);
                 let dep_node_index = self.encoder.borrow().send(profiler, key, fingerprint, edges);
@@ -1329,16 +1322,12 @@ impl<K: DepKind> CurrentDepGraph<K> {
     ) {
         let node = &prev_graph.index_to_node(prev_index);
         debug_assert!(
-            !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node),
+            !self.new_node_to_index.lock_shard_by_value(node).contains_key(node),
             "node from previous graph present in new node collection"
         );
     }
 }
 
-/// The capacity of the `reads` field `SmallVec`
-const TASK_DEPS_READS_CAP: usize = 8;
-type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
-
 #[derive(Debug, Clone, Copy)]
 pub enum TaskDepsRef<'a, K: DepKind> {
     /// New dependencies can be added to the
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 0fd9e35d6dc..272028d35bf 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -1,10 +1,12 @@
 pub mod debug;
 mod dep_node;
+mod edges;
 mod graph;
 mod query;
 mod serialized;
 
 pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId};
+pub use edges::EdgesVec;
 pub use graph::{
     hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef,
     WorkProduct, WorkProductMap,
@@ -157,4 +159,10 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder>
     fn read_deps<OP>(op: OP)
     where
         OP: for<'a> FnOnce(TaskDepsRef<'a, Self>);
+
+    fn from_u16(u: u16) -> Self;
+
+    fn to_u16(self) -> u16;
+
+    const MAX: u16;
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index edddfda6242..4ba0cb31d0b 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -1,6 +1,6 @@
 //! The data that we will serialize and deserialize.
 //!
-//! The dep-graph is serialized as a sequence of NodeInfo, with the dependencies
+//! Notionally, the dep-graph is a sequence of NodeInfo with the dependencies
 //! specified inline. The total number of nodes and edges are stored as the last
 //! 16 bytes of the file, so we can find them easily at decoding time.
 //!
@@ -11,17 +11,42 @@
 //! sequence of NodeInfos to the different arrays in SerializedDepGraph. Since the
 //! node and edge count are stored at the end of the file, all the arrays can be
 //! pre-allocated with the right length.
+//!
+//! The encoding of the de-pgraph is generally designed around the fact that fixed-size
+//! reads of encoded data are generally faster than variable-sized reads. Ergo we adopt
+//! essentially the same varint encoding scheme used in the rmeta format; the edge lists
+//! for each node on the graph store a 2-bit integer which is the number of bytes per edge
+//! index in that node's edge list. We effectively ignore that an edge index of 0 could be
+//! encoded with 0 bytes in order to not require 3 bits to store the byte width of the edges.
+//! The overhead of calculating the correct byte width for each edge is mitigated by
+//! building edge lists with [`EdgesVec`] which keeps a running max of the edges in a node.
+//!
+//! When we decode this data, we do not immediately create [`SerializedDepNodeIndex`] and
+//! instead keep the data in its denser serialized form which lets us turn our on-disk size
+//! efficiency directly into a peak memory reduction. When we convert these encoded-in-memory
+//! values into their fully-deserialized type, we use a fixed-size read of the encoded array
+//! then mask off any errant bytes we read. The array of edge index bytes is padded to permit this.
+//!
+//! We also encode and decode the entire rest of each node using [`SerializedNodeHeader`]
+//! to let this encoding and decoding be done in one fixed-size operation. These headers contain
+//! two [`Fingerprint`]s along with the serialized [`DepKind`], and the number of edge indices
+//! in the node and the number of bytes used to encode the edge indices for this node. The
+//! [`DepKind`], number of edges, and bytes per edge are all bit-packed together, if they fit.
+//! If the number of edges in this node does not fit in the bits available in the header, we
+//! store it directly after the header with leb128.
 
 use super::query::DepGraphQuery;
 use super::{DepKind, DepNode, DepNodeIndex};
+use crate::dep_graph::EdgesVec;
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fingerprint::PackedFingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
 use rustc_index::{Idx, IndexVec};
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
-use rustc_serialize::{Decodable, Decoder, Encodable};
-use smallvec::SmallVec;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use std::marker::PhantomData;
 
 // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
 // unused so that we can store multiple index types in `CompressedHybridIndex`,
@@ -31,6 +56,16 @@ rustc_index::newtype_index! {
     pub struct SerializedDepNodeIndex {}
 }
 
+const DEP_NODE_SIZE: usize = std::mem::size_of::<SerializedDepNodeIndex>();
+/// Amount of padding we need to add to the edge list data so that we can retrieve every
+/// SerializedDepNodeIndex with a fixed-size read then mask.
+const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
+/// Number of bits we need to store the number of used bytes in a SerializedDepNodeIndex.
+/// Note that wherever we encode byte widths like this we actually store the number of bytes used
+/// minus 1; for a 4-byte value we technically would have 5 widths to store, but using one byte to
+/// store zeroes (which are relatively rare) is a decent tradeoff to save a bit in our bitfields.
+const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
+
 /// Data for use when recompiling the **current crate**.
 #[derive(Debug)]
 pub struct SerializedDepGraph<K: DepKind> {
@@ -42,10 +77,10 @@ pub struct SerializedDepGraph<K: DepKind> {
     /// For each DepNode, stores the list of edges originating from that
     /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
     /// which holds the actual DepNodeIndices of the target nodes.
-    edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
-    /// A flattened list of all edge targets in the graph. Edge sources are
-    /// implicit in edge_list_indices.
-    edge_list_data: Vec<SerializedDepNodeIndex>,
+    edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>,
+    /// A flattened list of all edge targets in the graph, stored in the same
+    /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
+    edge_list_data: Vec<u8>,
     /// Reciprocal map to `nodes`.
     index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
 }
@@ -64,9 +99,35 @@ impl<K: DepKind> Default for SerializedDepGraph<K> {
 
 impl<K: DepKind> SerializedDepGraph<K> {
     #[inline]
-    pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] {
-        let targets = self.edge_list_indices[source];
-        &self.edge_list_data[targets.0 as usize..targets.1 as usize]
+    pub fn edge_targets_from(
+        &self,
+        source: SerializedDepNodeIndex,
+    ) -> impl Iterator<Item = SerializedDepNodeIndex> + '_ {
+        let header = self.edge_list_indices[source];
+        let mut raw = &self.edge_list_data[header.start()..];
+        // Figure out where the edge list for `source` ends by getting the start index of the next
+        // edge list, or the end of the array if this is the last edge.
+        let end = self
+            .edge_list_indices
+            .get(source + 1)
+            .map(|h| h.start())
+            .unwrap_or_else(|| self.edge_list_data.len() - DEP_NODE_PAD);
+
+        // The number of edges for this node is implicitly stored in the combination of the byte
+        // width and the length.
+        let bytes_per_index = header.bytes_per_index();
+        let len = (end - header.start()) / bytes_per_index;
+
+        // LLVM doesn't hoist EdgeHeader::mask so we do it ourselves.
+        let mask = header.mask();
+        (0..len).map(move |_| {
+            // Doing this slicing in this order ensures that the first bounds check suffices for
+            // all the others.
+            let index = &raw[..DEP_NODE_SIZE];
+            raw = &raw[bytes_per_index..];
+            let index = u32::from_le_bytes(index.try_into().unwrap()) & mask;
+            SerializedDepNodeIndex::from_u32(index)
+        })
     }
 
     #[inline]
@@ -84,11 +145,42 @@ impl<K: DepKind> SerializedDepGraph<K> {
         self.fingerprints[dep_node_index]
     }
 
+    #[inline]
     pub fn node_count(&self) -> usize {
         self.index.len()
     }
 }
 
+/// A packed representation of an edge's start index and byte width.
+///
+/// This is packed by stealing 2 bits from the start index, which means we only accomodate edge
+/// data arrays up to a quarter of our address space. Which seems fine.
+#[derive(Debug, Clone, Copy)]
+struct EdgeHeader {
+    repr: usize,
+}
+
+impl EdgeHeader {
+    #[inline]
+    fn start(self) -> usize {
+        self.repr >> DEP_NODE_WIDTH_BITS
+    }
+
+    #[inline]
+    fn bytes_per_index(self) -> usize {
+        (self.repr & mask(DEP_NODE_WIDTH_BITS)) + 1
+    }
+
+    #[inline]
+    fn mask(self) -> u32 {
+        mask(self.bytes_per_index() * 8) as u32
+    }
+}
+
+fn mask(bits: usize) -> usize {
+    usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits)
+}
+
 impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
     for SerializedDepGraph<K>
 {
@@ -107,32 +199,58 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
 
         debug!(?node_count, ?edge_count);
 
+        let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
+
         let mut nodes = IndexVec::with_capacity(node_count);
         let mut fingerprints = IndexVec::with_capacity(node_count);
         let mut edge_list_indices = IndexVec::with_capacity(node_count);
-        let mut edge_list_data = Vec::with_capacity(edge_count);
+        // This estimation assumes that all of the encoded bytes are for the edge lists or for the
+        // fixed-size node headers. But that's not necessarily true; if any edge list has a length
+        // that spills out of the size we can bit-pack into SerializedNodeHeader then some of the
+        // total serialized size is also used by leb128-encoded edge list lengths. Neglecting that
+        // contribution to graph_bytes means our estimation of the bytes needed for edge_list_data
+        // slightly overshoots. But it cannot overshoot by much; consider that the worse case is
+        // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at
+        // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128
+        // length is about the same fractional overhead and it amortizes for yet greater lengths.
+        let mut edge_list_data = Vec::with_capacity(
+            graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<K>>(),
+        );
 
         for _index in 0..node_count {
-            let dep_node: DepNode<K> = Decodable::decode(d);
-            let _i: SerializedDepNodeIndex = nodes.push(dep_node);
+            // Decode the header for this edge; the header packs together as many of the fixed-size
+            // fields as possible to limit the number of times we update decoder state.
+            let node_header = SerializedNodeHeader { bytes: d.read_array(), _marker: PhantomData };
+
+            let _i: SerializedDepNodeIndex = nodes.push(node_header.node());
             debug_assert_eq!(_i.index(), _index);
 
-            let fingerprint: Fingerprint = Decodable::decode(d);
-            let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
+            let _i: SerializedDepNodeIndex = fingerprints.push(node_header.fingerprint());
             debug_assert_eq!(_i.index(), _index);
 
-            // Deserialize edges -- sequence of DepNodeIndex
-            let len = d.read_usize();
-            let start = edge_list_data.len().try_into().unwrap();
-            for _ in 0..len {
-                let edge = Decodable::decode(d);
-                edge_list_data.push(edge);
-            }
-            let end = edge_list_data.len().try_into().unwrap();
-            let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end));
+            // If the length of this node's edge list is small, the length is stored in the header.
+            // If it is not, we fall back to another decoder call.
+            let num_edges = node_header.len().unwrap_or_else(|| d.read_usize());
+
+            // The edges index list uses the same varint strategy as rmeta tables; we select the
+            // number of byte elements per-array not per-element. This lets us read the whole edge
+            // list for a node with one decoder call and also use the on-disk format in memory.
+            let edges_len_bytes = node_header.bytes_per_index() * num_edges;
+            // The in-memory structure for the edges list stores the byte width of the edges on
+            // this node with the offset into the global edge data array.
+            let edges_header = node_header.edges_header(&edge_list_data);
+
+            edge_list_data.extend(d.read_raw_bytes(edges_len_bytes));
+
+            let _i: SerializedDepNodeIndex = edge_list_indices.push(edges_header);
             debug_assert_eq!(_i.index(), _index);
         }
 
+        // When we access the edge list data, we do a fixed-size read from the edge list data then
+        // mask off the bytes that aren't for that edge index, so the last read may dangle off the
+        // end of the array. This padding ensure it doesn't.
+        edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
+
         let index: FxHashMap<_, _> =
             nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
 
@@ -140,11 +258,154 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
     }
 }
 
-#[derive(Debug, Encodable, Decodable)]
-pub struct NodeInfo<K: DepKind> {
+/// A packed representation of all the fixed-size fields in a `NodeInfo`.
+///
+/// This stores in one byte array:
+/// * The `Fingerprint` in the `NodeInfo`
+/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo`
+/// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
+/// * The byte width of the encoded edges for this node
+/// * In whatever bits remain, the length of the edge list for this node, if it fits
+struct SerializedNodeHeader<K> {
+    // 2 bytes for the DepNode
+    // 16 for Fingerprint in DepNode
+    // 16 for Fingerprint in NodeInfo
+    bytes: [u8; 34],
+    _marker: PhantomData<K>,
+}
+
+// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only
+// to make the implementation of `SerializedNodeHeader` simpler.
+struct Unpacked<K> {
+    len: Option<usize>,
+    bytes_per_index: usize,
+    kind: K,
+    hash: PackedFingerprint,
+    fingerprint: Fingerprint,
+}
+
+// Bit fields, where
+// M: bits used to store the length of a node's edge list
+// N: bits used to store the byte width of elements of the edge list
+// are
+// 0..M    length of the edge
+// M..M+N  bytes per index
+// M+N..16 kind
+impl<K: DepKind> SerializedNodeHeader<K> {
+    const TOTAL_BITS: usize = std::mem::size_of::<K>() * 8;
+    const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS;
+    const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS;
+    const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize;
+    const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1;
+
+    #[inline]
+    fn new(node_info: &NodeInfo<K>) -> Self {
+        debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS);
+
+        let NodeInfo { node, fingerprint, edges } = node_info;
+
+        let mut head = node.kind.to_u16();
+
+        let free_bytes = edges.max_index().leading_zeros() as usize / 8;
+        let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1);
+        head |= (bytes_per_index as u16) << Self::KIND_BITS;
+
+        // Encode number of edges + 1 so that we can reserve 0 to indicate that the len doesn't fit
+        // in this bitfield.
+        if edges.len() <= Self::MAX_INLINE_LEN {
+            head |= (edges.len() as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
+        }
+
+        let hash: Fingerprint = node.hash.into();
+
+        // Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
+        let mut bytes = [0u8; 34];
+        bytes[..2].copy_from_slice(&head.to_le_bytes());
+        bytes[2..18].copy_from_slice(&hash.to_le_bytes());
+        bytes[18..].copy_from_slice(&fingerprint.to_le_bytes());
+
+        #[cfg(debug_assertions)]
+        {
+            let res = Self { bytes, _marker: PhantomData };
+            assert_eq!(node_info.fingerprint, res.fingerprint());
+            assert_eq!(node_info.node, res.node());
+            if let Some(len) = res.len() {
+                assert_eq!(node_info.edges.len(), len);
+            }
+        }
+        Self { bytes, _marker: PhantomData }
+    }
+
+    #[inline]
+    fn unpack(&self) -> Unpacked<K> {
+        let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
+        let hash = self.bytes[2..18].try_into().unwrap();
+        let fingerprint = self.bytes[18..].try_into().unwrap();
+
+        let kind = head & mask(Self::KIND_BITS) as u16;
+        let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
+        let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS);
+
+        Unpacked {
+            len: len.checked_sub(1),
+            bytes_per_index: bytes_per_index as usize + 1,
+            kind: DepKind::from_u16(kind),
+            hash: Fingerprint::from_le_bytes(hash).into(),
+            fingerprint: Fingerprint::from_le_bytes(fingerprint),
+        }
+    }
+
+    #[inline]
+    fn len(&self) -> Option<usize> {
+        self.unpack().len
+    }
+
+    #[inline]
+    fn bytes_per_index(&self) -> usize {
+        self.unpack().bytes_per_index
+    }
+
+    #[inline]
+    fn fingerprint(&self) -> Fingerprint {
+        self.unpack().fingerprint
+    }
+
+    #[inline]
+    fn node(&self) -> DepNode<K> {
+        let Unpacked { kind, hash, .. } = self.unpack();
+        DepNode { kind, hash }
+    }
+
+    #[inline]
+    fn edges_header(&self, edge_list_data: &[u8]) -> EdgeHeader {
+        EdgeHeader {
+            repr: (edge_list_data.len() << DEP_NODE_WIDTH_BITS) | (self.bytes_per_index() - 1),
+        }
+    }
+}
+
+#[derive(Debug)]
+struct NodeInfo<K: DepKind> {
     node: DepNode<K>,
     fingerprint: Fingerprint,
-    edges: SmallVec<[DepNodeIndex; 8]>,
+    edges: EdgesVec,
+}
+
+impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> {
+    fn encode(&self, e: &mut FileEncoder) {
+        let header = SerializedNodeHeader::new(self);
+        e.emit_raw_bytes(&header.bytes);
+
+        if header.len().is_none() {
+            e.emit_usize(self.edges.len());
+        }
+
+        let bytes_per_index = header.bytes_per_index();
+        for node_index in self.edges.iter() {
+            let bytes = node_index.as_u32().to_le_bytes();
+            e.emit_raw_bytes(&bytes[..bytes_per_index]);
+        }
+    }
 }
 
 struct Stat<K: DepKind> {
@@ -303,7 +564,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> {
         profiler: &SelfProfilerRef,
         node: DepNode<K>,
         fingerprint: Fingerprint,
-        edges: SmallVec<[DepNodeIndex; 8]>,
+        edges: EdgesVec,
     ) -> DepNodeIndex {
         let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph");
         let node = NodeInfo { node, fingerprint, edges };
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index f2b13f95def..b2177be0e36 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -79,15 +79,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
 
         src_hash.hash_stable(hcx, hasher);
 
-        // We are always in `Lines` form by the time we reach here.
-        assert!(self.lines.borrow().is_lines());
-        self.lines(|lines| {
+        {
+            // We are always in `Lines` form by the time we reach here.
+            assert!(self.lines.read().is_lines());
+            let lines = self.lines();
             // We only hash the relative position within this source_file
             lines.len().hash_stable(hcx, hasher);
             for &line in lines.iter() {
                 line.hash_stable(hcx, hasher);
             }
-        });
+        }
 
         // We only hash the relative position within this source_file
         multibyte_chars.len().hash_stable(hcx, hasher);
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 8c9e9cfad60..1944ac443ea 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(min_specialization)]
 #![feature(extern_types)]
 #![feature(let_chains)]
+#![feature(inline_const)]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index d8aa377af42..0240f012da0 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -55,7 +55,7 @@ where
     #[inline(always)]
     fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
         let key_hash = sharded::make_hash(key);
-        let lock = self.cache.get_shard_by_hash(key_hash).lock();
+        let lock = self.cache.lock_shard_by_hash(key_hash);
         let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
 
         if let Some((_, value)) = result { Some(*value) } else { None }
@@ -63,7 +63,7 @@ where
 
     #[inline]
     fn complete(&self, key: K, value: V, index: DepNodeIndex) {
-        let mut lock = self.cache.get_shard_by_value(&key).lock();
+        let mut lock = self.cache.lock_shard_by_value(&key);
         // We may be overwriting another value. This is all right, since the dep-graph
         // will check that the fingerprint matches.
         lock.insert(key, (value, index));
@@ -148,13 +148,13 @@ where
 
     #[inline(always)]
     fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
-        let lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
+        let lock = self.cache.lock_shard_by_hash(key.index() as u64);
         if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None }
     }
 
     #[inline]
     fn complete(&self, key: K, value: V, index: DepNodeIndex) {
-        let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
+        let mut lock = self.cache.lock_shard_by_hash(key.index() as u64);
         lock.insert(key, (value, index));
     }
 
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 9cba549a3b5..6c01dc3c00d 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -552,7 +552,9 @@ pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Regis
     // which in turn will wait on X causing a deadlock. We have a false dependency from
     // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
     // only considers the true dependency and won't detect a cycle.
-    assert!(found_cycle);
+    if !found_cycle {
+        panic!("deadlock detected");
+    }
 
     // FIXME: Ensure this won't cause a deadlock before we return
     for waiter in wakelist.into_iter() {
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 4fa168965a7..07db15e6d8b 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -158,7 +158,7 @@ where
         cache.complete(key, result, dep_node_index);
 
         let job = {
-            let mut lock = state.active.get_shard_by_value(&key).lock();
+            let mut lock = state.active.lock_shard_by_value(&key);
             match lock.remove(&key).unwrap() {
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
@@ -180,7 +180,7 @@ where
         // Poison the query so jobs waiting on it panic.
         let state = self.state;
         let job = {
-            let mut shard = state.active.get_shard_by_value(&self.key).lock();
+            let mut shard = state.active.lock_shard_by_value(&self.key);
             let job = match shard.remove(&self.key).unwrap() {
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
@@ -303,7 +303,7 @@ where
     Qcx: QueryContext,
 {
     let state = query.query_state(qcx);
-    let mut state_lock = state.active.get_shard_by_value(&key).lock();
+    let mut state_lock = state.active.lock_shard_by_value(&key);
 
     // For the parallel compiler we need to check both the query cache and query state structures
     // while holding the state lock to ensure that 1) the query has not yet completed and 2) the
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index f98918cba88..9a970f5db39 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -58,15 +58,16 @@ resolve_cannot_determine_import_resolution =
     cannot determine resolution for the import
     .note = import resolution is stuck, try simplifying other imports
 
+resolve_cannot_determine_macro_resolution =
+    cannot determine resolution for the {$kind} `{$path}`
+    .note = import resolution is stuck, try simplifying macro imports
+
 resolve_cannot_find_ident_in_this_scope =
     cannot find {$expected} `{$ident}` in this scope
 
 resolve_cannot_glob_import_possible_crates =
     cannot glob-import all possible crates
 
-resolve_cannot_use_self_type_here =
-    can't use `Self` here
-
 resolve_change_import_binding =
     you can use `as` to change the binding name of the import
 
@@ -86,9 +87,6 @@ resolve_const_not_member_of_trait =
     const `{$const_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
 
-resolve_const_param_from_outer_fn =
-    const parameter from outer function
-
 resolve_const_param_in_enum_discriminant =
     const parameters may not be used in enum discriminant values
 
@@ -115,10 +113,19 @@ resolve_forward_declared_generic_param =
     generic parameters with a default cannot use forward declared identifiers
     .label = defaulted generic parameters cannot be forward declared
 
-resolve_generic_params_from_outer_function =
-    can't use generic parameters from outer function
-    .label = use of generic parameter from outer function
-    .suggestion = try using a local generic parameter instead
+resolve_generic_params_from_outer_item =
+    can't use generic parameters from outer item
+    .label = use of generic parameter from outer item
+    .refer_to_type_directly = refer to the type directly here instead
+    .suggestion = try introducing a local generic parameter here
+
+resolve_generic_params_from_outer_item_const_param = const parameter from outer item
+
+resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`
+
+resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
+
+resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
 
 resolve_glob_import_doesnt_reexport =
     glob import doesn't reexport anything because no candidate is public enough
@@ -273,9 +280,6 @@ resolve_type_not_member_of_trait =
     type `{$type_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
 
-resolve_type_param_from_outer_fn =
-    type parameter from outer function
-
 resolve_type_param_in_enum_discriminant =
     type parameters may not be used in enum discriminant values
 
@@ -311,9 +315,6 @@ resolve_unreachable_label_suggestion_use_similarly_named =
 resolve_unreachable_label_with_similar_name_exists =
     a label with a similar name exists but is unreachable
 
-resolve_use_a_type_here_instead =
-    use a type here instead
-
 resolve_variable_bound_with_different_mode =
     variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
     .label = bound in different ways
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d99fc07a7cd..9b7fd76d103 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -553,43 +553,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         resolution_error: ResolutionError<'a>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
+            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
+                use errs::GenericParamsFromOuterItemLabel as Label;
+                let mut err = errs::GenericParamsFromOuterItem {
                     span,
-                    E0401,
-                    "can't use generic parameters from outer function",
-                );
-                err.span_label(span, "use of generic parameter from outer function");
+                    label: None,
+                    refer_to_type_directly: None,
+                    sugg: None,
+                };
 
                 let sm = self.tcx.sess.source_map();
                 let def_id = match outer_res {
                     Res::SelfTyParam { .. } => {
-                        err.span_label(span, "can't use `Self` here");
-                        return err;
+                        err.label = Some(Label::SelfTyParam(span));
+                        return self.tcx.sess.create_err(err);
                     }
                     Res::SelfTyAlias { alias_to: def_id, .. } => {
-                        err.span_label(
-                            reduce_impl_span_to_impl_keyword(sm, self.def_span(def_id)),
-                            "`Self` type implicitly declared here, by this `impl`",
-                        );
-                        err.span_label(span, "use a type here instead");
-                        return err;
+                        err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
+                            sm,
+                            self.def_span(def_id),
+                        )));
+                        err.refer_to_type_directly = Some(span);
+                        return self.tcx.sess.create_err(err);
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
-                        err.span_label(self.def_span(def_id), "type parameter from outer function");
+                        err.label = Some(Label::TyParam(self.def_span(def_id)));
                         def_id
                     }
                     Res::Def(DefKind::ConstParam, def_id) => {
-                        err.span_label(
-                            self.def_span(def_id),
-                            "const parameter from outer function",
-                        );
+                        err.label = Some(Label::ConstParam(self.def_span(def_id)));
                         def_id
                     }
                     _ => {
                         bug!(
-                            "GenericParamsFromOuterFunction should only be used with \
+                            "GenericParamsFromOuterItem should only be used with \
                             Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
                             DefKind::ConstParam"
                         );
@@ -597,9 +594,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 };
 
                 if let HasGenericParams::Yes(span) = has_generic_params {
-                    // Try to retrieve the span of the function signature and generate a new
-                    // message with a local type or const parameter.
-                    let sugg_msg = "try using a local generic parameter instead";
                     let name = self.tcx.item_name(def_id);
                     let (span, snippet) = if span.is_empty() {
                         let snippet = format!("<{name}>");
@@ -609,11 +603,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         let snippet = format!("{name}, ");
                         (span, snippet)
                     };
-                    // Suggest the modification to the user
-                    err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
+                    err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
                 }
 
-                err
+                self.tcx.sess.create_err(err)
             }
             ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
                 .tcx
@@ -2753,7 +2746,13 @@ fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
     for item in items {
         if let ItemKind::Use(..) = item.kind {
             if is_span_suitable_for_use_injection(item.span) {
-                return Some(item.span.shrink_to_lo());
+                let mut lo = item.span.lo();
+                for attr in &item.attrs {
+                    if attr.span.eq_ctxt(item.span) {
+                        lo = std::cmp::min(lo, attr.span.lo());
+                    }
+                }
+                return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index e4b89c65853..72ff959bbd6 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -33,6 +33,40 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate)
 pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span);
 
 #[derive(Diagnostic)]
+#[diag(resolve_generic_params_from_outer_item, code = "E0401")]
+pub(crate) struct GenericParamsFromOuterItem {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) label: Option<GenericParamsFromOuterItemLabel>,
+    #[label(resolve_refer_to_type_directly)]
+    pub(crate) refer_to_type_directly: Option<Span>,
+    #[subdiagnostic]
+    pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum GenericParamsFromOuterItemLabel {
+    #[label(resolve_generic_params_from_outer_item_self_ty_param)]
+    SelfTyParam(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_self_ty_alias)]
+    SelfTyAlias(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_ty_param)]
+    TyParam(#[primary_span] Span),
+    #[label(resolve_generic_params_from_outer_item_const_param)]
+    ConstParam(#[primary_span] Span),
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(resolve_suggestion, code = "{snippet}", applicability = "maybe-incorrect")]
+pub(crate) struct GenericParamsFromOuterItemSugg {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) snippet: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")]
 pub(crate) struct NameAlreadyUsedInParameterList {
     #[primary_span]
@@ -655,6 +689,16 @@ pub(crate) struct CannotDetermineImportResolution {
 }
 
 #[derive(Diagnostic)]
+#[diag(resolve_cannot_determine_macro_resolution)]
+#[note]
+pub(crate) struct CannotDetermineMacroResolution {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) kind: &'static str,
+    pub(crate) path: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(resolve_cannot_be_reexported_private, code = "E0364")]
 pub(crate) struct CannotBeReexportedPrivate {
     #[primary_span]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 61e05b65f90..4817484f564 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1229,10 +1229,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
+                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
                         );
                     }
                     return Res::Err;
@@ -1296,10 +1293,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
+                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
                         );
                     }
                     return Res::Err;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 486d60eab21..d40b1b2e3a9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2450,7 +2450,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(if self.r.tcx.features().generic_const_items {
+                        HasGenericParams::Yes(generics.span)
+                    } else {
+                        HasGenericParams::No
+                    }),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::ConstItem,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b757f42eaa0..a29aec24688 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -34,7 +34,7 @@ use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArg
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{Lrc, MappedReadGuard};
+use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
 use rustc_errors::{
     Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
 };
@@ -186,8 +186,8 @@ struct BindingError {
 
 #[derive(Debug)]
 enum ResolutionError<'a> {
-    /// Error E0401: can't use type or const parameters from outer function.
-    GenericParamsFromOuterFunction(Res, HasGenericParams),
+    /// Error E0401: can't use type or const parameters from outer item.
+    GenericParamsFromOuterItem(Res, HasGenericParams),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
@@ -1544,7 +1544,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         ))
     }
 
-    fn cstore(&self) -> MappedReadGuard<'_, CStore> {
+    fn cstore(&self) -> FreezeReadGuard<'_, CStore> {
         CStore::from_tcx(self.tcx)
     }
 
@@ -1599,7 +1599,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         });
 
         // Make sure we don't mutate the cstore from here on.
-        self.tcx.untracked().cstore.leak();
+        self.tcx.untracked().cstore.freeze();
     }
 
     fn traits_in_scope(
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 1199290a4d1..82060716575 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -2,7 +2,8 @@
 //! interface provided by `Resolver` to macro expander.
 
 use crate::errors::{
-    self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive,
+    self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
+    MacroExpectedFound, RemoveSurroundingDerive,
 };
 use crate::Namespace::*;
 use crate::{BuiltinMacroState, Determinacy};
@@ -719,13 +720,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 // even if speculative `resolve_path` returned nothing previously, so we skip this
                 // less informative error if the privacy error is reported elsewhere.
                 if this.privacy_errors.is_empty() {
-                    let msg = format!(
-                        "cannot determine resolution for the {} `{}`",
-                        kind.descr(),
-                        Segment::names_to_string(path)
-                    );
-                    let msg_note = "import resolution is stuck, try simplifying macro imports";
-                    this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit();
+                    this.tcx.sess.emit_err(CannotDetermineMacroResolution {
+                        span,
+                        kind: kind.descr(),
+                        path: Segment::names_to_string(path),
+                    });
                 }
             }
         };
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index ba7417b6dda..7c41c32d022 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -2,9 +2,11 @@ use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
 use rustc_ast as ast;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::{InnerSpan, Span, DUMMY_SP};
+use std::ops::Range;
 use std::{cmp, mem};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -462,3 +464,88 @@ fn collect_link_data<'input, 'callback>(
 
     display_text.map(String::into_boxed_str)
 }
+
+/// Returns a span encompassing all the document fragments.
+pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
+    if fragments.is_empty() {
+        return None;
+    }
+    let start = fragments[0].span;
+    if start == DUMMY_SP {
+        return None;
+    }
+    let end = fragments.last().expect("no doc strings provided").span;
+    Some(start.to(end))
+}
+
+/// 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.
+pub fn source_span_for_markdown_range(
+    tcx: TyCtxt<'_>,
+    markdown: &str,
+    md_range: &Range<usize>,
+    fragments: &[DocFragment],
+) -> Option<Span> {
+    let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
+
+    if !is_all_sugared_doc {
+        return None;
+    }
+
+    let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?;
+
+    let starting_line = markdown[..md_range.start].matches('\n').count();
+    let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
+
+    // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
+    // CRLF and LF line endings the same way.
+    let mut src_lines = snippet.split_terminator('\n');
+    let md_lines = markdown.split_terminator('\n');
+
+    // The number of bytes from the source span to the markdown span that are not part
+    // of the markdown, like comment markers.
+    let mut start_bytes = 0;
+    let mut end_bytes = 0;
+
+    'outer: for (line_no, md_line) in md_lines.enumerate() {
+        loop {
+            let source_line = src_lines.next()?;
+            match source_line.find(md_line) {
+                Some(offset) => {
+                    if line_no == starting_line {
+                        start_bytes += offset;
+
+                        if starting_line == ending_line {
+                            break 'outer;
+                        }
+                    } else if line_no == ending_line {
+                        end_bytes += offset;
+                        break 'outer;
+                    } else if line_no < starting_line {
+                        start_bytes += source_line.len() - md_line.len();
+                    } else {
+                        end_bytes += source_line.len() - md_line.len();
+                    }
+                    break;
+                }
+                None => {
+                    // Since this is a source line that doesn't include a markdown line,
+                    // we have to count the newline that we split from earlier.
+                    if line_no <= starting_line {
+                        start_bytes += source_line.len() + 1;
+                    } else {
+                        end_bytes += source_line.len() + 1;
+                    }
+                }
+            }
+        }
+    }
+
+    Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
+        md_range.start + start_bytes,
+        md_range.end + start_bytes + end_bytes,
+    )))
+}
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 0ffc537eee0..f1b7e8d9ae0 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -353,7 +353,7 @@ impl<'a> MemDecoder<'a> {
     }
 
     #[inline]
-    fn read_array<const N: usize>(&mut self) -> [u8; N] {
+    pub fn read_array<const N: usize>(&mut self) -> [u8; N] {
         self.read_raw_bytes(N).try_into().unwrap()
     }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f00472f181d..29de4c8856e 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -381,6 +381,24 @@ pub enum DebugInfo {
     Full,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum DebugInfoCompression {
+    None,
+    Zlib,
+    Zstd,
+}
+
+impl ToString for DebugInfoCompression {
+    fn to_string(&self) -> String {
+        match self {
+            DebugInfoCompression::None => "none",
+            DebugInfoCompression::Zlib => "zlib",
+            DebugInfoCompression::Zstd => "zstd",
+        }
+        .to_owned()
+    }
+}
+
 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
 /// uses DWARF for debug-information.
@@ -1015,6 +1033,7 @@ impl Default for Options {
             crate_types: Vec::new(),
             optimize: OptLevel::No,
             debuginfo: DebugInfo::None,
+            debuginfo_compression: DebugInfoCompression::None,
             lint_opts: Vec::new(),
             lint_cap: None,
             describe_lints: false,
@@ -1084,12 +1103,6 @@ impl Options {
     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
     }
-
-    #[allow(rustc::bad_opt_access)]
-    pub fn incremental_relative_spans(&self) -> bool {
-        self.unstable_opts.incremental_relative_spans
-            || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
-    }
 }
 
 impl UnstableOptions {
@@ -2160,12 +2173,6 @@ fn collect_print_requests(
     prints.extend(matches.opt_strs("print").into_iter().map(|req| {
         let (req, out) = split_out_file_name(&req);
 
-        if out.is_some() && !unstable_opts.unstable_options {
-            handler.early_error(
-                "the `-Z unstable-options` flag must also be passed to \
-                 enable the path print option",
-            );
-        }
         let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) {
             Some((_, PrintKind::TargetSpec)) => {
                 if unstable_opts.unstable_options {
@@ -2283,6 +2290,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
     if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
 }
 
+fn select_debuginfo_compression(
+    _handler: &EarlyErrorHandler,
+    unstable_opts: &UnstableOptions,
+) -> DebugInfoCompression {
+    unstable_opts.debuginfo_compression
+}
+
 pub(crate) fn parse_assert_incr_state(
     handler: &EarlyErrorHandler,
     opt_assertion: &Option<String>,
@@ -2758,6 +2772,8 @@ pub fn build_session_options(
     // for more details.
     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
     let debuginfo = select_debuginfo(matches, &cg);
+    let debuginfo_compression: DebugInfoCompression =
+        select_debuginfo_compression(handler, &unstable_opts);
 
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
@@ -2834,6 +2850,7 @@ pub fn build_session_options(
         crate_types,
         optimize: opt_level,
         debuginfo,
+        debuginfo_compression,
         lint_opts,
         lint_cap,
         describe_lints,
@@ -2959,6 +2976,7 @@ pub mod nightly_options {
     ) {
         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
         let really_allows_unstable_options = match_is_nightly_build(matches);
+        let mut nightly_options_on_stable = 0;
 
         for opt in flags.iter() {
             if opt.stability == OptionStability::Stable {
@@ -2979,20 +2997,27 @@ pub mod nightly_options {
             }
             match opt.stability {
                 OptionStability::Unstable => {
+                    nightly_options_on_stable += 1;
                     let msg = format!(
                         "the option `{}` is only accepted on the nightly compiler",
                         opt.name
                     );
                     let _ = handler.early_error_no_abort(msg);
-                    handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
-                    handler.early_help(
-                        "consider switching to a nightly toolchain: `rustup default nightly`",
-                    );
-                    handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
                 }
                 OptionStability::Stable => {}
             }
         }
+        if nightly_options_on_stable > 0 {
+            handler
+                .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
+            handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
+            handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
+            handler.early_error(format!(
+                "{} nightly option{} were parsed",
+                nightly_options_on_stable,
+                if nightly_options_on_stable > 1 { "s" } else { "" }
+            ));
+        }
     }
 }
 
@@ -3119,11 +3144,11 @@ impl PpMode {
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
     use super::{
-        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
-        InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
-        OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
-        SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
-        TraitSolver, TrimmedDefPaths,
+        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
+        ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
+        LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
+        Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
+        SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -3201,6 +3226,7 @@ pub(crate) mod dep_tracking {
         OptLevel,
         LtoCli,
         DebugInfo,
+        DebugInfoCompression,
         UnstableFeatures,
         NativeLib,
         NativeLibKind,
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index c53a355b533..d816842b02b 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -7,7 +7,7 @@ use crate::utils::NativeLibKind;
 use crate::Session;
 use rustc_ast as ast;
 use rustc_data_structures::owned_slice::OwnedSlice;
-use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock};
+use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -258,8 +258,8 @@ pub trait CrateStore: std::fmt::Debug {
 pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend;
 
 pub struct Untracked {
-    pub cstore: RwLock<Box<CrateStoreDyn>>,
+    pub cstore: FreezeLock<Box<CrateStoreDyn>>,
     /// Reference span for definitions.
     pub source_span: AppendOnlyIndexVec<LocalDefId, Span>,
-    pub definitions: RwLock<Definitions>,
+    pub definitions: FreezeLock<Definitions>,
 }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 40099de707b..7c2068a157c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -139,6 +139,7 @@ top_level_options!(
         /// can influence whether overflow checks are done or not.
         debug_assertions: bool [TRACKED],
         debuginfo: DebugInfo [TRACKED],
+        debuginfo_compression: DebugInfoCompression [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH],
         lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH],
         describe_lints: bool [UNTRACKED],
@@ -376,6 +377,7 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
+    pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -782,6 +784,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_debuginfo_compression(
+        slot: &mut DebugInfoCompression,
+        v: Option<&str>,
+    ) -> bool {
+        match v {
+            Some("none") => *slot = DebugInfoCompression::None,
+            Some("zlib") => *slot = DebugInfoCompression::Zlib,
+            Some("zstd") => *slot = DebugInfoCompression::Zstd,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
         match v.and_then(LinkerFlavorCli::from_str) {
             Some(lf) => *slot = Some(lf),
@@ -1424,6 +1439,8 @@ options! {
         "emit discriminators and other data necessary for AutoFDO"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
         "emit line numbers debug info inside macros (default: no)"),
+    debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
+        "compress debug info sections (none, zlib, zstd, default: none)"),
     deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
         "deduplicate identical diagnostics (default: yes)"),
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
@@ -1524,9 +1541,6 @@ options! {
     incremental_info: bool = (false, parse_bool, [UNTRACKED],
         "print high-level information about incremental reuse (or the lack thereof) \
         (default: no)"),
-    #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
-    incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
-        "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
         "verify incr. comp. hashes of green query instances (default: no)"),
     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 86db2edab7b..9bff9017881 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -204,6 +204,12 @@ pub struct Session {
 
     /// The version of the rustc process, possibly including a commit hash and description.
     pub cfg_version: &'static str,
+
+    /// All commandline args used to invoke the compiler, with @file args fully expanded.
+    /// This will only be used within debug info, e.g. in the pdb file on windows
+    /// This is mainly useful for other tools that reads that debuginfo to figure out
+    /// how to call the compiler with the same arguments.
+    pub expanded_args: Vec<String>,
 }
 
 pub struct PerfStats {
@@ -1325,6 +1331,7 @@ pub fn build_session(
     target_override: Option<Target>,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
+    expanded_args: Vec<String>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
     // normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -1467,6 +1474,7 @@ pub fn build_session(
         target_features: Default::default(),
         unstable_target_features: Default::default(),
         cfg_version,
+        expanded_args,
     };
 
     validate_commandline_args_with_session_available(&sess);
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 73b8e060dd8..4203990ab05 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -16,7 +16,6 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_interface::{interface, Queries};
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::EarlyErrorHandler;
 pub use rustc_span::def_id::{CrateNum, DefId};
 
 fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
@@ -233,7 +232,6 @@ where
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 52ba4bd4e57..321ee790509 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -42,6 +42,10 @@ impl<'tcx> Context for Tables<'tcx> {
         self.tcx.def_path_str(self[def_id])
     }
 
+    fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Span {
+        self.tcx.def_span(self[def_id]).stable(self)
+    }
+
     fn all_local_items(&mut self) -> stable_mir::CrateItems {
         self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
     }
@@ -78,9 +82,9 @@ impl<'tcx> Context for Tables<'tcx> {
         impl_trait.stable(self)
     }
 
-    fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
-        let def_id = self[item.0];
-        let mir = self.tcx.optimized_mir(def_id);
+    fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
+        let def_id = self[item];
+        let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id));
         stable_mir::mir::Body {
             blocks: mir
                 .basic_blocks
@@ -103,8 +107,13 @@ impl<'tcx> Context for Tables<'tcx> {
     }
 
     fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind {
-        let ty = self.types[ty.0];
-        ty.stable(self)
+        self.types[ty.0].clone().stable(self)
+    }
+
+    fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty {
+        let n = self.types.len();
+        self.types.push(MaybeStable::Stable(kind));
+        stable_mir::ty::Ty(n)
     }
 
     fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
@@ -128,20 +137,47 @@ impl<'tcx> Context for Tables<'tcx> {
     }
 }
 
+#[derive(Clone)]
+pub enum MaybeStable<S, R> {
+    Stable(S),
+    Rustc(R),
+}
+
+impl<'tcx, S, R> MaybeStable<S, R> {
+    fn stable(self, tables: &mut Tables<'tcx>) -> S
+    where
+        R: Stable<'tcx, T = S>,
+    {
+        match self {
+            MaybeStable::Stable(s) => s,
+            MaybeStable::Rustc(r) => r.stable(tables),
+        }
+    }
+}
+
+impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
+    fn eq(&self, other: &R) -> bool {
+        match self {
+            MaybeStable::Stable(_) => false,
+            MaybeStable::Rustc(r) => r == other,
+        }
+    }
+}
+
 pub struct Tables<'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub def_ids: Vec<DefId>,
     pub alloc_ids: Vec<AllocId>,
-    pub types: Vec<Ty<'tcx>>,
+    pub types: Vec<MaybeStable<stable_mir::ty::TyKind, Ty<'tcx>>>,
 }
 
 impl<'tcx> Tables<'tcx> {
     fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
-        if let Some(id) = self.types.iter().position(|&t| t == ty) {
+        if let Some(id) = self.types.iter().position(|t| *t == ty) {
             return stable_mir::ty::Ty(id);
         }
         let id = self.types.len();
-        self.types.push(ty);
+        self.types.push(MaybeStable::Rustc(ty));
         stable_mir::ty::Ty(id)
     }
 }
@@ -1097,14 +1133,13 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
                         tables,
                     ))
                 }
-                ty::ParamCt(param) => stable_mir::ty::ConstantKind::ParamCt(opaque(&param)),
+                ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
                 ty::ErrorCt(_) => unreachable!(),
                 ty::InferCt(_) => unreachable!(),
                 ty::BoundCt(_, _) => unimplemented!(),
                 ty::PlaceholderCt(_) => unimplemented!(),
                 ty::Unevaluated(uv) => {
                     stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                        ty: tables.intern_ty(self.ty()),
                         def: tables.const_def(uv.def),
                         args: uv.args.stable(tables),
                         promoted: None,
@@ -1112,10 +1147,19 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
                 }
                 ty::ExprCt(_) => unimplemented!(),
             },
+            ty: tables.intern_ty(self.ty()),
         }
     }
 }
 
+impl<'tcx> Stable<'tcx> for ty::ParamConst {
+    type T = stable_mir::ty::ParamConst;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::ParamConst;
+        ParamConst { index: self.index, name: self.name.to_string() }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for ty::ParamTy {
     type T = stable_mir::ty::ParamTy;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -1184,22 +1228,27 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
 }
 
 impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
-    type T = stable_mir::ty::ConstantKind;
+    type T = stable_mir::ty::Const;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         match *self {
-            ConstantKind::Ty(c) => c.stable(tables).literal,
-            ConstantKind::Unevaluated(unev_const, ty) => {
-                stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                    ty: tables.intern_ty(ty),
-                    def: tables.const_def(unev_const.def),
-                    args: unev_const.args.stable(tables),
-                    promoted: unev_const.promoted.map(|u| u.as_u32()),
-                })
-            }
-            ConstantKind::Val(val, ty) => {
-                stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(ty, val, tables))
-            }
+            ConstantKind::Ty(c) => c.stable(tables),
+            ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
+                literal: stable_mir::ty::ConstantKind::Unevaluated(
+                    stable_mir::ty::UnevaluatedConst {
+                        def: tables.const_def(unev_const.def),
+                        args: unev_const.args.stable(tables),
+                        promoted: unev_const.promoted.map(|u| u.as_u32()),
+                    },
+                ),
+                ty: tables.intern_ty(ty),
+            },
+            ConstantKind::Val(val, ty) => stable_mir::ty::Const {
+                literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
+                    ty, val, tables,
+                )),
+                ty: tables.intern_ty(ty),
+            },
         }
     }
 }
@@ -1248,7 +1297,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
             ty::GenericParamDefKind::Type { has_default, synthetic } => {
                 GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
             }
-            ty::GenericParamDefKind::Const { has_default } => {
+            ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => {
                 GenericParamDefKind::Const { has_default: *has_default }
             }
         }
diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs
new file mode 100644
index 00000000000..831cfb40a15
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/fold.rs
@@ -0,0 +1,230 @@
+use std::ops::ControlFlow;
+
+use crate::rustc_internal::Opaque;
+
+use super::ty::{
+    Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind,
+    GenericArgs, Promoted, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst,
+};
+
+pub trait Folder: Sized {
+    type Break;
+    fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
+        ty.super_fold(self)
+    }
+    fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
+        c.super_fold(self)
+    }
+}
+
+pub trait Foldable: Sized + Clone {
+    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        self.super_fold(folder)
+    }
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self>;
+}
+
+impl Foldable for Ty {
+    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        folder.visit_ty(self)
+    }
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut kind = self.kind();
+        match &mut kind {
+            super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?,
+            super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?,
+            super::ty::TyKind::Param(_) => {}
+            super::ty::TyKind::Bound(_, _) => {}
+        }
+        ControlFlow::Continue(kind.into())
+    }
+}
+
+impl Foldable for Const {
+    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        folder.fold_const(self)
+    }
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut this = self.clone();
+        match &mut this.literal {
+            super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?,
+            super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?,
+            super::ty::ConstantKind::Param(_) => {}
+        }
+        this.ty = this.ty.fold(folder)?;
+        ControlFlow::Continue(this)
+    }
+}
+
+impl Foldable for Opaque {
+    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(self.clone())
+    }
+}
+
+impl Foldable for Allocation {
+    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(self.clone())
+    }
+}
+
+impl Foldable for UnevaluatedConst {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let UnevaluatedConst { def, args, promoted } = self;
+        ControlFlow::Continue(UnevaluatedConst {
+            def: def.fold(folder)?,
+            args: args.fold(folder)?,
+            promoted: promoted.fold(folder)?,
+        })
+    }
+}
+
+impl Foldable for ConstDef {
+    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(self.clone())
+    }
+}
+
+impl<T: Foldable> Foldable for Option<T> {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(match self {
+            Some(val) => Some(val.fold(folder)?),
+            None => None,
+        })
+    }
+}
+
+impl Foldable for Promoted {
+    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(self.clone())
+    }
+}
+
+impl Foldable for GenericArgs {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(GenericArgs(self.0.fold(folder)?))
+    }
+}
+
+impl Foldable for GenericArgKind {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut this = self.clone();
+        match &mut this {
+            GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?,
+            GenericArgKind::Type(t) => *t = t.fold(folder)?,
+            GenericArgKind::Const(c) => *c = c.fold(folder)?,
+        }
+        ControlFlow::Continue(this)
+    }
+}
+
+impl Foldable for RigidTy {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut this = self.clone();
+        match &mut this {
+            RigidTy::Bool
+            | RigidTy::Char
+            | RigidTy::Int(_)
+            | RigidTy::Uint(_)
+            | RigidTy::Float(_)
+            | RigidTy::Never
+            | RigidTy::Foreign(_)
+            | RigidTy::Str => {}
+            RigidTy::Array(t, c) => {
+                *t = t.fold(folder)?;
+                *c = c.fold(folder)?;
+            }
+            RigidTy::Slice(inner) => *inner = inner.fold(folder)?,
+            RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?,
+            RigidTy::Ref(_, ty, _) => *ty = ty.fold(folder)?,
+            RigidTy::FnDef(_, args) => *args = args.fold(folder)?,
+            RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?,
+            RigidTy::Closure(_, args) => *args = args.fold(folder)?,
+            RigidTy::Generator(_, args, _) => *args = args.fold(folder)?,
+            RigidTy::Dynamic(pred, r, _) => {
+                *pred = pred.fold(folder)?;
+                *r = r.fold(folder)?;
+            }
+            RigidTy::Tuple(fields) => *fields = fields.fold(folder)?,
+            RigidTy::Adt(_, args) => *args = args.fold(folder)?,
+        }
+        ControlFlow::Continue(this)
+    }
+}
+
+impl<T: Foldable> Foldable for Vec<T> {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut this = self.clone();
+        for arg in &mut this {
+            *arg = arg.fold(folder)?;
+        }
+        ControlFlow::Continue(this)
+    }
+}
+
+impl<T: Foldable> Foldable for Binder<T> {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(Self {
+            value: self.value.fold(folder)?,
+            bound_vars: self.bound_vars.clone(),
+        })
+    }
+}
+
+impl Foldable for ExistentialPredicate {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        let mut this = self.clone();
+        match &mut this {
+            ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?,
+            ExistentialPredicate::Projection(p) => {
+                p.term = p.term.fold(folder)?;
+                p.generic_args = p.generic_args.fold(folder)?;
+            }
+            ExistentialPredicate::AutoTrait(_) => {}
+        }
+        ControlFlow::Continue(this)
+    }
+}
+
+impl Foldable for TermKind {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(match self {
+            TermKind::Type(t) => TermKind::Type(t.fold(folder)?),
+            TermKind::Const(c) => TermKind::Const(c.fold(folder)?),
+        })
+    }
+}
+
+impl Foldable for FnSig {
+    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
+        ControlFlow::Continue(Self {
+            inputs_and_output: self.inputs_and_output.fold(folder)?,
+            c_variadic: self.c_variadic,
+            unsafety: self.unsafety,
+            abi: self.abi.clone(),
+        })
+    }
+}
+
+pub enum Never {}
+
+/// In order to instantiate a `Foldable`'s generic parameters with specific arguments,
+/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params
+/// with the entries in its list.
+impl Folder for GenericArgs {
+    type Break = Never;
+
+    fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
+        ControlFlow::Continue(match ty.kind() {
+            TyKind::Param(p) => self[p],
+            _ => *ty,
+        })
+    }
+
+    fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
+        ControlFlow::Continue(match &c.literal {
+            ConstantKind::Param(p) => self[p.clone()].clone(),
+            _ => c.clone(),
+        })
+    }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
index 72f719c2a5e..449ca4b8145 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/body.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -1,6 +1,6 @@
 use crate::rustc_internal::Opaque;
 use crate::stable_mir::ty::{
-    AdtDef, ClosureDef, Const, ConstantKind, GeneratorDef, GenericArgs, Movability, Region,
+    AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region,
 };
 use crate::stable_mir::{self, ty::Ty, Span};
 
@@ -352,7 +352,7 @@ type UserTypeAnnotationIndex = usize;
 pub struct Constant {
     pub span: Span,
     pub user_ty: Option<UserTypeAnnotationIndex>,
-    pub literal: ConstantKind,
+    pub literal: Const,
 }
 
 #[derive(Clone, Debug)]
@@ -391,7 +391,7 @@ pub enum Mutability {
     Mut,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
 pub enum Safety {
     Unsafe,
     Normal,
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index f9eafd9de7a..508e3aa1291 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -20,6 +20,7 @@ use self::ty::{
 };
 use crate::rustc_smir::Tables;
 
+pub mod fold;
 pub mod mir;
 pub mod ty;
 pub mod visitor;
@@ -86,7 +87,11 @@ pub struct CrateItem(pub(crate) DefId);
 
 impl CrateItem {
     pub fn body(&self) -> mir::Body {
-        with(|cx| cx.mir_body(self))
+        with(|cx| cx.mir_body(self.0))
+    }
+
+    pub fn span(&self) -> ty::Span {
+        with(|cx| cx.span_of_an_item(self.0))
     }
 }
 
@@ -137,7 +142,7 @@ pub trait Context {
     fn entry_fn(&mut self) -> Option<CrateItem>;
     /// Retrieve all items of the local crate that have a MIR associated with them.
     fn all_local_items(&mut self) -> CrateItems;
-    fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
+    fn mir_body(&mut self, item: DefId) -> mir::Body;
     fn all_trait_decls(&mut self) -> TraitDecls;
     fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
     fn all_trait_impls(&mut self) -> ImplTraitDecls;
@@ -155,9 +160,15 @@ pub trait Context {
     /// Prints the name of given `DefId`
     fn name_of_def_id(&self, def_id: DefId) -> String;
 
+    /// `Span` of an item
+    fn span_of_an_item(&mut self, def_id: DefId) -> Span;
+
     /// Obtain the representation of a type.
     fn ty_kind(&mut self, ty: Ty) -> TyKind;
 
+    /// Create a new `Ty` from scratch without information from rustc.
+    fn mk_ty(&mut self, kind: TyKind) -> Ty;
+
     /// HACK: Until we have fully stable consumers, we need an escape hatch
     /// to get `DefId`s out of `CrateItem`s.
     fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>));
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 1db6b1e3d28..54cba1263b7 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1,18 +1,36 @@
-use super::{mir::Mutability, mir::Safety, with, AllocId, DefId};
+use super::{
+    mir::Safety,
+    mir::{Body, Mutability},
+    with, AllocId, DefId,
+};
 use crate::rustc_internal::Opaque;
+use std::fmt::{self, Debug, Formatter};
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 pub struct Ty(pub usize);
 
+impl Debug for Ty {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish()
+    }
+}
+
 impl Ty {
     pub fn kind(&self) -> TyKind {
         with(|context| context.ty_kind(*self))
     }
 }
 
+impl From<TyKind> for Ty {
+    fn from(value: TyKind) -> Self {
+        with(|context| context.mk_ty(value))
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct Const {
     pub literal: ConstantKind,
+    pub ty: Ty,
 }
 
 type Ident = Opaque;
@@ -88,6 +106,12 @@ pub struct ForeignDef(pub(crate) DefId);
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct FnDef(pub(crate) DefId);
 
+impl FnDef {
+    pub fn body(&self) -> Body {
+        with(|ctx| ctx.mir_body(self.0))
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct ClosureDef(pub(crate) DefId);
 
@@ -121,6 +145,22 @@ pub struct ImplDef(pub(crate) DefId);
 #[derive(Clone, Debug)]
 pub struct GenericArgs(pub Vec<GenericArgKind>);
 
+impl std::ops::Index<ParamTy> for GenericArgs {
+    type Output = Ty;
+
+    fn index(&self, index: ParamTy) -> &Self::Output {
+        self.0[index.index as usize].expect_ty()
+    }
+}
+
+impl std::ops::Index<ParamConst> for GenericArgs {
+    type Output = Const;
+
+    fn index(&self, index: ParamConst) -> &Self::Output {
+        self.0[index.index as usize].expect_const()
+    }
+}
+
 #[derive(Clone, Debug)]
 pub enum GenericArgKind {
     Lifetime(Region),
@@ -128,6 +168,28 @@ pub enum GenericArgKind {
     Const(Const),
 }
 
+impl GenericArgKind {
+    /// Panic if this generic argument is not a type, otherwise
+    /// return the type.
+    #[track_caller]
+    pub fn expect_ty(&self) -> &Ty {
+        match self {
+            GenericArgKind::Type(ty) => ty,
+            _ => panic!("{self:?}"),
+        }
+    }
+
+    /// Panic if this generic argument is not a const, otherwise
+    /// return the const.
+    #[track_caller]
+    pub fn expect_const(&self) -> &Const {
+        match self {
+            GenericArgKind::Const(c) => c,
+            _ => panic!("{self:?}"),
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 pub enum TermKind {
     Type(Ty),
@@ -287,12 +349,17 @@ pub struct Allocation {
 pub enum ConstantKind {
     Allocated(Allocation),
     Unevaluated(UnevaluatedConst),
-    ParamCt(Opaque),
+    Param(ParamConst),
+}
+
+#[derive(Clone, Debug)]
+pub struct ParamConst {
+    pub index: u32,
+    pub name: String,
 }
 
 #[derive(Clone, Debug)]
 pub struct UnevaluatedConst {
-    pub ty: Ty,
     pub def: ConstDef,
     pub args: GenericArgs,
     pub promoted: Option<Promoted>,
diff --git a/compiler/rustc_smir/src/stable_mir/visitor.rs b/compiler/rustc_smir/src/stable_mir/visitor.rs
index c928eb1381f..c86063d2ed6 100644
--- a/compiler/rustc_smir/src/stable_mir/visitor.rs
+++ b/compiler/rustc_smir/src/stable_mir/visitor.rs
@@ -30,11 +30,12 @@ impl Visitable for Ty {
     }
     fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
         match self.kind() {
-            super::ty::TyKind::RigidTy(ty) => ty.visit(visitor),
-            super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor),
-            super::ty::TyKind::Param(_) => todo!(),
-            super::ty::TyKind::Bound(_, _) => todo!(),
+            super::ty::TyKind::RigidTy(ty) => ty.visit(visitor)?,
+            super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor)?,
+            super::ty::TyKind::Param(_) => {}
+            super::ty::TyKind::Bound(_, _) => {}
         }
+        ControlFlow::Continue(())
     }
 }
 
@@ -44,10 +45,11 @@ impl Visitable for Const {
     }
     fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
         match &self.literal {
-            super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor),
-            super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor),
-            super::ty::ConstantKind::ParamCt(param) => param.visit(visitor),
+            super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?,
+            super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?,
+            super::ty::ConstantKind::Param(_) => {}
         }
+        self.ty.visit(visitor)
     }
 }
 
@@ -65,8 +67,7 @@ impl Visitable for Allocation {
 
 impl Visitable for UnevaluatedConst {
     fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
-        let UnevaluatedConst { ty, def, args, promoted } = self;
-        ty.visit(visitor)?;
+        let UnevaluatedConst { def, args, promoted } = self;
         def.visit(visitor)?;
         args.visit(visitor)?;
         promoted.visit(visitor)
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index f1a6e9059d7..68724c48037 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -33,7 +33,7 @@ extern crate rustc_macros;
 #[macro_use]
 extern crate tracing;
 
-use rustc_data_structures::AtomicRef;
+use rustc_data_structures::{cold_path, AtomicRef};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
@@ -64,7 +64,7 @@ pub mod fatal_error;
 pub mod profiling;
 
 use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
-use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
 
 use std::borrow::Cow;
 use std::cmp::{self, Ordering};
@@ -510,10 +510,6 @@ impl SpanData {
     pub fn is_dummy(self) -> bool {
         self.lo.0 == 0 && self.hi.0 == 0
     }
-    #[inline]
-    pub fn is_visible(self, sm: &SourceMap) -> bool {
-        !self.is_dummy() && sm.is_span_accessible(self.span())
-    }
     /// Returns `true` if `self` fully encloses `other`.
     pub fn contains(self, other: Self) -> bool {
         self.lo <= other.lo && other.hi <= self.hi
@@ -573,15 +569,9 @@ impl Span {
         self.data().with_parent(ctxt)
     }
 
-    /// Returns `true` if this is a dummy span with any hygienic context.
-    #[inline]
-    pub fn is_dummy(self) -> bool {
-        self.data_untracked().is_dummy()
-    }
-
     #[inline]
     pub fn is_visible(self, sm: &SourceMap) -> bool {
-        self.data_untracked().is_visible(sm)
+        !self.is_dummy() && sm.is_span_accessible(self)
     }
 
     /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
@@ -1206,7 +1196,6 @@ pub enum ExternalSourceKind {
     AbsentOk,
     /// A failed attempt has been made to load the external source.
     AbsentErr,
-    Unneeded,
 }
 
 impl ExternalSource {
@@ -1343,13 +1332,13 @@ pub struct SourceFile {
     pub src_hash: SourceFileHash,
     /// The external source code (used for external crates, which will have a `None`
     /// value as `self.src`.
-    pub external_src: Lock<ExternalSource>,
+    pub external_src: FreezeLock<ExternalSource>,
     /// The start position of this source in the `SourceMap`.
     pub start_pos: BytePos,
     /// The byte length of this source.
     pub source_len: RelativeBytePos,
     /// Locations of lines beginnings in the source code.
-    pub lines: Lock<SourceFileLines>,
+    pub lines: FreezeLock<SourceFileLines>,
     /// Locations of multi-byte characters in the source code.
     pub multibyte_chars: Vec<MultiByteChar>,
     /// Width of characters that are not narrow in the source code.
@@ -1368,10 +1357,10 @@ impl Clone for SourceFile {
             name: self.name.clone(),
             src: self.src.clone(),
             src_hash: self.src_hash,
-            external_src: Lock::new(self.external_src.borrow().clone()),
+            external_src: self.external_src.clone(),
             start_pos: self.start_pos,
             source_len: self.source_len,
-            lines: Lock::new(self.lines.borrow().clone()),
+            lines: self.lines.clone(),
             multibyte_chars: self.multibyte_chars.clone(),
             non_narrow_chars: self.non_narrow_chars.clone(),
             normalized_pos: self.normalized_pos.clone(),
@@ -1389,64 +1378,63 @@ impl<S: Encoder> Encodable<S> for SourceFile {
         self.source_len.encode(s);
 
         // We are always in `Lines` form by the time we reach here.
-        assert!(self.lines.borrow().is_lines());
-        self.lines(|lines| {
-            // Store the length.
-            s.emit_u32(lines.len() as u32);
-
-            // Compute and store the difference list.
-            if lines.len() != 0 {
-                let max_line_length = if lines.len() == 1 {
-                    0
-                } else {
-                    lines
-                        .array_windows()
-                        .map(|&[fst, snd]| snd - fst)
-                        .map(|bp| bp.to_usize())
-                        .max()
-                        .unwrap()
-                };
-
-                let bytes_per_diff: usize = match max_line_length {
-                    0..=0xFF => 1,
-                    0x100..=0xFFFF => 2,
-                    _ => 4,
-                };
-
-                // Encode the number of bytes used per diff.
-                s.emit_u8(bytes_per_diff as u8);
-
-                // Encode the first element.
-                assert_eq!(lines[0], RelativeBytePos(0));
-
-                // Encode the difference list.
-                let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
-                let num_diffs = lines.len() - 1;
-                let mut raw_diffs;
-                match bytes_per_diff {
-                    1 => {
-                        raw_diffs = Vec::with_capacity(num_diffs);
-                        for diff in diff_iter {
-                            raw_diffs.push(diff.0 as u8);
-                        }
+        assert!(self.lines.read().is_lines());
+        let lines = self.lines();
+        // Store the length.
+        s.emit_u32(lines.len() as u32);
+
+        // Compute and store the difference list.
+        if lines.len() != 0 {
+            let max_line_length = if lines.len() == 1 {
+                0
+            } else {
+                lines
+                    .array_windows()
+                    .map(|&[fst, snd]| snd - fst)
+                    .map(|bp| bp.to_usize())
+                    .max()
+                    .unwrap()
+            };
+
+            let bytes_per_diff: usize = match max_line_length {
+                0..=0xFF => 1,
+                0x100..=0xFFFF => 2,
+                _ => 4,
+            };
+
+            // Encode the number of bytes used per diff.
+            s.emit_u8(bytes_per_diff as u8);
+
+            // Encode the first element.
+            assert_eq!(lines[0], RelativeBytePos(0));
+
+            // Encode the difference list.
+            let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
+            let num_diffs = lines.len() - 1;
+            let mut raw_diffs;
+            match bytes_per_diff {
+                1 => {
+                    raw_diffs = Vec::with_capacity(num_diffs);
+                    for diff in diff_iter {
+                        raw_diffs.push(diff.0 as u8);
                     }
-                    2 => {
-                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
-                        for diff in diff_iter {
-                            raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
-                        }
+                }
+                2 => {
+                    raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                    for diff in diff_iter {
+                        raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
                     }
-                    4 => {
-                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
-                        for diff in diff_iter {
-                            raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
-                        }
+                }
+                4 => {
+                    raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                    for diff in diff_iter {
+                        raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
                     }
-                    _ => unreachable!(),
                 }
-                s.emit_raw_bytes(&raw_diffs);
+                _ => unreachable!(),
             }
-        });
+            s.emit_raw_bytes(&raw_diffs);
+        }
 
         self.multibyte_chars.encode(s);
         self.non_narrow_chars.encode(s);
@@ -1488,8 +1476,8 @@ impl<D: Decoder> Decodable<D> for SourceFile {
             src_hash,
             // Unused - the metadata decoder will construct
             // a new SourceFile, filling in `external_src` properly
-            external_src: Lock::new(ExternalSource::Unneeded),
-            lines: Lock::new(lines),
+            external_src: FreezeLock::frozen(ExternalSource::Unneeded),
+            lines: FreezeLock::new(lines),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1530,10 +1518,10 @@ impl SourceFile {
             name,
             src: Some(Lrc::new(src)),
             src_hash,
-            external_src: Lock::new(ExternalSource::Unneeded),
+            external_src: FreezeLock::frozen(ExternalSource::Unneeded),
             start_pos: BytePos::from_u32(0),
             source_len: RelativeBytePos::from_u32(source_len),
-            lines: Lock::new(SourceFileLines::Lines(lines)),
+            lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1542,65 +1530,82 @@ impl SourceFile {
         })
     }
 
-    pub fn lines<F, R>(&self, f: F) -> R
-    where
-        F: FnOnce(&[RelativeBytePos]) -> R,
-    {
-        let mut guard = self.lines.borrow_mut();
-        match &*guard {
-            SourceFileLines::Lines(lines) => f(lines),
-            SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) => {
-                // Convert from "diffs" form to "lines" form.
-                let num_lines = num_diffs + 1;
-                let mut lines = Vec::with_capacity(num_lines);
-                let mut line_start = RelativeBytePos(0);
-                lines.push(line_start);
-
-                assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
-                match bytes_per_diff {
-                    1 => {
-                        lines.extend(raw_diffs.into_iter().map(|&diff| {
-                            line_start = line_start + RelativeBytePos(diff as u32);
-                            line_start
-                        }));
-                    }
-                    2 => {
-                        lines.extend((0..*num_diffs).map(|i| {
-                            let pos = bytes_per_diff * i;
-                            let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
-                            let diff = u16::from_le_bytes(bytes);
-                            line_start = line_start + RelativeBytePos(diff as u32);
-                            line_start
-                        }));
-                    }
-                    4 => {
-                        lines.extend((0..*num_diffs).map(|i| {
-                            let pos = bytes_per_diff * i;
-                            let bytes = [
-                                raw_diffs[pos],
-                                raw_diffs[pos + 1],
-                                raw_diffs[pos + 2],
-                                raw_diffs[pos + 3],
-                            ];
-                            let diff = u32::from_le_bytes(bytes);
-                            line_start = line_start + RelativeBytePos(diff);
-                            line_start
-                        }));
-                    }
-                    _ => unreachable!(),
-                }
-                let res = f(&lines);
-                *guard = SourceFileLines::Lines(lines);
-                res
+    /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it.
+    fn convert_diffs_to_lines_frozen(&self) {
+        let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
+
+        let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
+            SourceFileLines::Diffs(diffs) => diffs,
+            SourceFileLines::Lines(..) => {
+                FreezeWriteGuard::freeze(guard);
+                return;
             }
+        };
+
+        // Convert from "diffs" form to "lines" form.
+        let num_lines = num_diffs + 1;
+        let mut lines = Vec::with_capacity(num_lines);
+        let mut line_start = RelativeBytePos(0);
+        lines.push(line_start);
+
+        assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
+        match bytes_per_diff {
+            1 => {
+                lines.extend(raw_diffs.into_iter().map(|&diff| {
+                    line_start = line_start + RelativeBytePos(diff as u32);
+                    line_start
+                }));
+            }
+            2 => {
+                lines.extend((0..*num_diffs).map(|i| {
+                    let pos = bytes_per_diff * i;
+                    let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
+                    let diff = u16::from_le_bytes(bytes);
+                    line_start = line_start + RelativeBytePos(diff as u32);
+                    line_start
+                }));
+            }
+            4 => {
+                lines.extend((0..*num_diffs).map(|i| {
+                    let pos = bytes_per_diff * i;
+                    let bytes = [
+                        raw_diffs[pos],
+                        raw_diffs[pos + 1],
+                        raw_diffs[pos + 2],
+                        raw_diffs[pos + 3],
+                    ];
+                    let diff = u32::from_le_bytes(bytes);
+                    line_start = line_start + RelativeBytePos(diff);
+                    line_start
+                }));
+            }
+            _ => unreachable!(),
         }
+
+        *guard = SourceFileLines::Lines(lines);
+
+        FreezeWriteGuard::freeze(guard);
+    }
+
+    pub fn lines(&self) -> &[RelativeBytePos] {
+        if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
+            return &lines[..];
+        }
+
+        cold_path(|| {
+            self.convert_diffs_to_lines_frozen();
+            if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
+                return &lines[..];
+            }
+            unreachable!()
+        })
     }
 
     /// Returns the `BytePos` of the beginning of the current line.
     pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
         let pos = self.relative_position(pos);
         let line_index = self.lookup_line(pos).unwrap();
-        let line_start_pos = self.lines(|lines| lines[line_index]);
+        let line_start_pos = self.lines()[line_index];
         self.absolute_position(line_start_pos)
     }
 
@@ -1612,35 +1617,37 @@ impl SourceFile {
     where
         F: FnOnce() -> Option<String>,
     {
-        if matches!(
-            *self.external_src.borrow(),
-            ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
-        ) {
+        if !self.external_src.is_frozen() {
             let src = get_src();
-            let mut external_src = self.external_src.borrow_mut();
-            // Check that no-one else have provided the source while we were getting it
-            if let ExternalSource::Foreign {
-                kind: src_kind @ ExternalSourceKind::AbsentOk, ..
-            } = &mut *external_src
-            {
-                if let Some(mut src) = src {
-                    // The src_hash needs to be computed on the pre-normalized src.
-                    if self.src_hash.matches(&src) {
-                        normalize_src(&mut src);
-                        *src_kind = ExternalSourceKind::Present(Lrc::new(src));
-                        return true;
-                    }
+            let src = src.and_then(|mut src| {
+                // The src_hash needs to be computed on the pre-normalized src.
+                self.src_hash.matches(&src).then(|| {
+                    normalize_src(&mut src);
+                    src
+                })
+            });
+
+            self.external_src.try_write().map(|mut external_src| {
+                if let ExternalSource::Foreign {
+                    kind: src_kind @ ExternalSourceKind::AbsentOk,
+                    ..
+                } = &mut *external_src
+                {
+                    *src_kind = if let Some(src) = src {
+                        ExternalSourceKind::Present(Lrc::new(src))
+                    } else {
+                        ExternalSourceKind::AbsentErr
+                    };
                 } else {
-                    *src_kind = ExternalSourceKind::AbsentErr;
+                    panic!("unexpected state {:?}", *external_src)
                 }
 
-                false
-            } else {
-                self.src.is_some() || external_src.get_source().is_some()
-            }
-        } else {
-            self.src.is_some() || self.external_src.borrow().get_source().is_some()
+                // Freeze this so we don't try to load the source again.
+                FreezeWriteGuard::freeze(external_src)
+            });
         }
+
+        self.src.is_some() || self.external_src.read().get_source().is_some()
     }
 
     /// Gets a line from the list of pre-computed line-beginnings.
@@ -1658,7 +1665,7 @@ impl SourceFile {
         }
 
         let begin = {
-            let line = self.lines(|lines| lines.get(line_number).copied())?;
+            let line = self.lines().get(line_number).copied()?;
             line.to_usize()
         };
 
@@ -1682,7 +1689,7 @@ impl SourceFile {
     }
 
     pub fn count_lines(&self) -> usize {
-        self.lines(|lines| lines.len())
+        self.lines().len()
     }
 
     #[inline]
@@ -1705,7 +1712,7 @@ impl SourceFile {
     /// number. If the source_file is empty or the position is located before the
     /// first line, `None` is returned.
     pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
-        self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
+        self.lines().partition_point(|x| x <= &pos).checked_sub(1)
     }
 
     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
@@ -1713,15 +1720,13 @@ impl SourceFile {
             return self.start_pos..self.start_pos;
         }
 
-        self.lines(|lines| {
-            assert!(line_index < lines.len());
-            if line_index == (lines.len() - 1) {
-                self.absolute_position(lines[line_index])..self.end_position()
-            } else {
-                self.absolute_position(lines[line_index])
-                    ..self.absolute_position(lines[line_index + 1])
-            }
-        })
+        let lines = self.lines();
+        assert!(line_index < lines.len());
+        if line_index == (lines.len() - 1) {
+            self.absolute_position(lines[line_index])..self.end_position()
+        } else {
+            self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
+        }
     }
 
     /// Returns whether or not the file contains the given `SourceMap` byte
@@ -1807,7 +1812,7 @@ impl SourceFile {
         match self.lookup_line(pos) {
             Some(a) => {
                 let line = a + 1; // Line numbers start at 1
-                let linebpos = self.lines(|lines| lines[a]);
+                let linebpos = self.lines()[a];
                 let linechpos = self.bytepos_to_file_charpos(linebpos);
                 let col = chpos - linechpos;
                 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
@@ -1827,7 +1832,7 @@ impl SourceFile {
         let (line, col_or_chpos) = self.lookup_file_pos(pos);
         if line > 0 {
             let col = col_or_chpos;
-            let linebpos = self.lines(|lines| lines[line - 1]);
+            let linebpos = self.lines()[line - 1];
             let col_display = {
                 let start_width_idx = self
                     .non_narrow_chars
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 81730f2f608..68727a6c40e 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -328,7 +328,7 @@ impl SourceMap {
         name_hash: Hash128,
         source_len: u32,
         cnum: CrateNum,
-        file_local_lines: Lock<SourceFileLines>,
+        file_local_lines: FreezeLock<SourceFileLines>,
         multibyte_chars: Vec<MultiByteChar>,
         non_narrow_chars: Vec<NonNarrowChar>,
         normalized_pos: Vec<NormalizedPos>,
@@ -340,7 +340,7 @@ impl SourceMap {
             name: filename,
             src: None,
             src_hash,
-            external_src: Lock::new(ExternalSource::Foreign {
+            external_src: FreezeLock::new(ExternalSource::Foreign {
                 kind: ExternalSourceKind::AbsentOk,
                 metadata_index,
             }),
@@ -564,7 +564,7 @@ impl SourceMap {
                 end: (local_end.sf.name.clone(), local_end.sf.start_pos),
             })))
         } else {
-            self.ensure_source_file_source_present(local_begin.sf.clone());
+            self.ensure_source_file_source_present(&local_begin.sf);
 
             let start_index = local_begin.pos.to_usize();
             let end_index = local_end.pos.to_usize();
@@ -581,7 +581,7 @@ impl SourceMap {
 
             if let Some(ref src) = local_begin.sf.src {
                 extract_source(src, start_index, end_index)
-            } else if let Some(src) = local_begin.sf.external_src.borrow().get_source() {
+            } else if let Some(src) = local_begin.sf.external_src.read().get_source() {
                 extract_source(src, start_index, end_index)
             } else {
                 Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
@@ -873,7 +873,7 @@ impl SourceMap {
             let sp = sp.data();
             let local_begin = self.lookup_byte_offset(sp.lo);
             let start_index = local_begin.pos.to_usize();
-            let src = local_begin.sf.external_src.borrow();
+            let src = local_begin.sf.external_src.read();
 
             let snippet = if let Some(ref src) = local_begin.sf.src {
                 Some(&src[start_index..])
@@ -983,7 +983,7 @@ impl SourceMap {
             return 1;
         }
 
-        let src = local_begin.sf.external_src.borrow();
+        let src = local_begin.sf.external_src.read();
 
         let snippet = if let Some(src) = &local_begin.sf.src {
             src
@@ -1030,7 +1030,7 @@ impl SourceMap {
         self.files().iter().fold(0, |a, f| a + f.count_lines())
     }
 
-    pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
+    pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool {
         source_file.add_external_src(|| {
             let FileName::Real(ref name) = source_file.name else {
                 return None;
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 7689e6afac5..e393db02064 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -1,6 +1,6 @@
 use super::*;
 
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{FreezeLock, Lrc};
 
 fn init_source_map() -> SourceMap {
     let sm = SourceMap::new(FilePathMapping::empty());
@@ -246,7 +246,7 @@ fn t10() {
         name_hash,
         source_len.to_u32(),
         CrateNum::new(0),
-        lines,
+        FreezeLock::new(lines.read().clone()),
         multibyte_chars,
         non_narrow_chars,
         normalized_pos,
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index 1eea0f63ca0..93ab154601f 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -1,9 +1,3 @@
-// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
-// One format is used for keeping span data inline,
-// another contains index into an out-of-line span interner.
-// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
-// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
-
 use crate::def_id::{DefIndex, LocalDefId};
 use crate::hygiene::SyntaxContext;
 use crate::SPAN_TRACK;
@@ -13,59 +7,69 @@ use rustc_data_structures::fx::FxIndexSet;
 
 /// A compressed span.
 ///
-/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length, parent and
-/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
-/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
+/// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only
+/// takes up 8 bytes, with less space for the length, parent and context. The
+/// vast majority (99.9%+) of `SpanData` instances can be made to fit within
+/// those 8 bytes. Any `SpanData` whose fields don't fit into a `Span` are
 /// stored in a separate interner table, and the `Span` will index into that
 /// table. Interning is rare enough that the cost is low, but common enough
 /// that the code is exercised regularly.
 ///
 /// An earlier version of this code used only 4 bytes for `Span`, but that was
 /// slower because only 80--90% of spans could be stored inline (even less in
-/// very large crates) and so the interner was used a lot more.
+/// very large crates) and so the interner was used a lot more. That version of
+/// the code also predated the storage of parents.
+///
+/// There are four different span forms.
 ///
-/// Inline (compressed) format with no parent:
-/// - `span.base_or_index == span_data.lo`
-/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
-/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
+/// Inline-context format (requires non-huge length, non-huge context, and no parent):
+/// - `span.lo_or_index == span_data.lo`
+/// - `span.len_with_tag_or_marker == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
-/// Interned format with inline `SyntaxContext`:
-/// - `span.base_or_index == index` (indexes into the interner table)
-/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
-/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
+/// Inline-parent format (requires non-huge length, root context, and non-huge parent):
+/// - `span.lo_or_index == span_data.lo`
+/// - `span.len_with_tag_or_marker & !PARENT_TAG == len == span_data.hi - span_data.lo`
+///   (must be `<= MAX_LEN`)
+/// - `span.len_with_tag_or_marker` has top bit (`PARENT_TAG`) set
+/// - `span.ctxt_or_parent_or_marker == span_data.parent` (must be `<= MAX_CTXT`)
 ///
-/// Inline (compressed) format with root context:
-/// - `span.base_or_index == span_data.lo`
-/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
-/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
-/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+/// Partially-interned format (requires non-huge context):
+/// - `span.lo_or_index == index` (indexes into the interner table)
+/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER`
+/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
-/// Interned format:
-/// - `span.base_or_index == index` (indexes into the interner table)
-/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
-/// - `span.ctxt_or_tag == CTXT_TAG`
+/// Fully-interned format (all cases not covered above):
+/// - `span.lo_or_index == index` (indexes into the interner table)
+/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER`
+/// - `span.ctxt_or_parent_or_marker == CTXT_INTERNED_MARKER`
 ///
-/// The inline form uses 0 for the tag value (rather than 1) so that we don't
-/// need to mask out the tag bit when getting the length, and so that the
-/// dummy span can be all zeroes.
+/// The partially-interned form requires looking in the interning table for
+/// lo and length, but the context is stored inline as well as interned.
+/// This is useful because context lookups are often done in isolation, and
+/// inline lookups are quicker.
 ///
 /// Notes about the choice of field sizes:
-/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base`
-///   values never cause interning. The number of bits needed for `base`
+/// - `lo` is 32 bits in both `Span` and `SpanData`, which means that `lo`
+///   values never cause interning. The number of bits needed for `lo`
 ///   depends on the crate size. 32 bits allows up to 4 GiB of code in a crate.
-/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits
-///   in `SpanData`, which means that large `len` values will cause interning.
-///   The number of bits needed for `len` does not depend on the crate size.
-///   The most common numbers of bits for `len` are from 0 to 7, with a peak usually
-///   at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
-///   for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
-///   dozens of times in a typical crate.
-/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
-///   large `ctxt` values will cause interning. The number of bits needed for
-///   `ctxt` values depend partly on the crate size and partly on the form of
-///   the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`,
-///   but larger crates might need more than 16 bits.
+///   Having no compression on this field means there is no performance cliff
+///   if a crate exceeds a particular size.
+/// - `len` is ~15 bits in `Span` (a u16, minus 1 bit for PARENT_TAG) and 32
+///   bits in `SpanData`, which means that large `len` values will cause
+///   interning. The number of bits needed for `len` does not depend on the
+///   crate size. The most common numbers of bits for `len` are from 0 to 7,
+///   with a peak usually at 3 or 4, and then it drops off quickly from 8
+///   onwards. 15 bits is enough for 99.99%+ of cases, but larger values
+///   (sometimes 20+ bits) might occur dozens of times in a typical crate.
+/// - `ctxt_or_parent_or_marker` is 16 bits in `Span` and two 32 bit fields in
+///   `SpanData`, which means intering will happen if `ctxt` is large, if
+///   `parent` is large, or if both values are non-zero. The number of bits
+///   needed for `ctxt` values depend partly on the crate size and partly on
+///   the form of the code. No crates in `rustc-perf` need more than 15 bits
+///   for `ctxt_or_parent_or_marker`, but larger crates might need more than 16
+///   bits. The number of bits needed for `parent` hasn't been measured,
+///   because `parent` isn't currently used by default.
 ///
 /// In order to reliably use parented spans in incremental compilation,
 /// the dependency to the parent definition's span. This is performed
@@ -74,19 +78,22 @@ use rustc_data_structures::fx::FxIndexSet;
 #[derive(Clone, Copy, Eq, PartialEq, Hash)]
 #[rustc_pass_by_value]
 pub struct Span {
-    base_or_index: u32,
-    len_or_tag: u16,
-    ctxt_or_tag: u16,
+    lo_or_index: u32,
+    len_with_tag_or_marker: u16,
+    ctxt_or_parent_or_marker: u16,
 }
 
-const LEN_TAG: u16 = 0b1111_1111_1111_1111;
-const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
-const MAX_LEN: u32 = 0b0111_1111_1111_1111;
-const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
-const MAX_CTXT: u32 = CTXT_TAG - 1;
+// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
+// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
+const MAX_LEN: u32 = 0b0111_1111_1111_1110;
+const MAX_CTXT: u32 = 0b0111_1111_1111_1110;
+const PARENT_TAG: u16 = 0b1000_0000_0000_0000;
+const BASE_LEN_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111;
+const CTXT_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111;
 
-/// Dummy span, both position and length are zero, syntax context is zero as well.
-pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 };
+/// The dummy span has zero position, length, and context, and no parent.
+pub const DUMMY_SP: Span =
+    Span { lo_or_index: 0, len_with_tag_or_marker: 0, ctxt_or_parent_or_marker: 0 };
 
 impl Span {
     #[inline]
@@ -100,39 +107,43 @@ impl Span {
             std::mem::swap(&mut lo, &mut hi);
         }
 
-        let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
-
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
-            let len_or_tag = len as u16;
-            debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+        let (lo2, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-            if let Some(parent) = parent {
-                // Inline format with parent.
-                let len_or_tag = len_or_tag | PARENT_MASK;
-                let parent2 = parent.local_def_index.as_u32();
-                if ctxt2 == SyntaxContext::root().as_u32()
-                    && parent2 <= MAX_CTXT
-                    && len_or_tag < LEN_TAG
-                {
-                    debug_assert_ne!(len_or_tag, LEN_TAG);
-                    return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
-                }
-            } else {
-                // Inline format with ctxt.
-                debug_assert_ne!(len_or_tag, LEN_TAG);
+        if len <= MAX_LEN {
+            if ctxt2 <= MAX_CTXT && parent.is_none() {
+                // Inline-context format.
                 return Span {
-                    base_or_index: base,
-                    len_or_tag: len as u16,
-                    ctxt_or_tag: ctxt2 as u16,
+                    lo_or_index: lo2,
+                    len_with_tag_or_marker: len as u16,
+                    ctxt_or_parent_or_marker: ctxt2 as u16,
+                };
+            } else if ctxt2 == SyntaxContext::root().as_u32()
+                && let Some(parent) = parent
+                && let parent2 = parent.local_def_index.as_u32()
+                && parent2 <= MAX_CTXT
+            {
+                // Inline-parent format.
+                return Span {
+                    lo_or_index: lo2,
+                    len_with_tag_or_marker: PARENT_TAG | len as u16,
+                    ctxt_or_parent_or_marker: parent2 as u16
                 };
             }
         }
 
-        // Interned format.
+        // Partially-interned or fully-interned format.
         let index =
             with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
-        let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
-        Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+        let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT {
+            ctxt2 as u16 // partially-interned
+        } else {
+            CTXT_INTERNED_MARKER // fully-interned
+        };
+        Span {
+            lo_or_index: index,
+            len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER,
+            ctxt_or_parent_or_marker,
+        }
     }
 
     #[inline]
@@ -148,56 +159,80 @@ impl Span {
     /// This function must not be used outside the incremental engine.
     #[inline]
     pub fn data_untracked(self) -> SpanData {
-        if self.len_or_tag != LEN_TAG {
-            // Inline format.
-            if self.len_or_tag & PARENT_MASK == 0 {
-                debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            if self.len_with_tag_or_marker & PARENT_TAG == 0 {
+                // Inline-context format.
+                let len = self.len_with_tag_or_marker as u32;
+                debug_assert!(len <= MAX_LEN);
                 SpanData {
-                    lo: BytePos(self.base_or_index),
-                    hi: BytePos(self.base_or_index + self.len_or_tag as u32),
-                    ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+                    lo: BytePos(self.lo_or_index),
+                    hi: BytePos(self.lo_or_index + len),
+                    ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),
                     parent: None,
                 }
             } else {
-                let len = self.len_or_tag & !PARENT_MASK;
-                debug_assert!(len as u32 <= MAX_LEN);
-                let parent =
-                    LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+                // Inline-parent format.
+                let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
+                debug_assert!(len <= MAX_LEN);
+                let parent = LocalDefId {
+                    local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32),
+                };
                 SpanData {
-                    lo: BytePos(self.base_or_index),
-                    hi: BytePos(self.base_or_index + len as u32),
+                    lo: BytePos(self.lo_or_index),
+                    hi: BytePos(self.lo_or_index + len),
                     ctxt: SyntaxContext::root(),
                     parent: Some(parent),
                 }
             }
         } else {
-            // Interned format.
-            let index = self.base_or_index;
+            // Fully-interned or partially-interned format. In either case,
+            // the interned value contains all the data, so we don't need to
+            // distinguish them.
+            let index = self.lo_or_index;
             with_span_interner(|interner| interner.spans[index as usize])
         }
     }
 
+    /// Returns `true` if this is a dummy span with any hygienic context.
+    #[inline]
+    pub fn is_dummy(self) -> bool {
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            // Inline-context or inline-parent format.
+            let lo = self.lo_or_index;
+            let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
+            debug_assert!(len <= MAX_LEN);
+            lo == 0 && len == 0
+        } else {
+            // Fully-interned or partially-interned format.
+            let index = self.lo_or_index;
+            let data = with_span_interner(|interner| interner.spans[index as usize]);
+            data.lo == BytePos(0) && data.hi == BytePos(0)
+        }
+    }
+
     /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
+    /// It's a cut-down version of `data_untracked`.
     #[inline]
     pub fn ctxt(self) -> SyntaxContext {
-        let ctxt_or_tag = self.ctxt_or_tag as u32;
-        // Check for interned format.
-        if self.len_or_tag == LEN_TAG {
-            if ctxt_or_tag == CTXT_TAG {
-                // Fully interned format.
-                let index = self.base_or_index;
-                with_span_interner(|interner| interner.spans[index as usize].ctxt)
+        if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
+            if self.len_with_tag_or_marker & PARENT_TAG == 0 {
+                // Inline-context format.
+                SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
             } else {
-                // Interned format with inline ctxt.
-                SyntaxContext::from_u32(ctxt_or_tag)
+                // Inline-parent format. We know that the SyntaxContext is root.
+                SyntaxContext::root()
             }
-        } else if self.len_or_tag & PARENT_MASK == 0 {
-            // Inline format with inline ctxt.
-            SyntaxContext::from_u32(ctxt_or_tag)
         } else {
-            // Inline format with inline parent.
-            // We know that the SyntaxContext is root.
-            SyntaxContext::root()
+            if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
+                // Partially-interned format. This path avoids looking up the
+                // interned value, and is the whole point of the
+                // partially-interned format.
+                SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
+            } else {
+                // Fully-interned format.
+                let index = self.lo_or_index;
+                with_span_interner(|interner| interner.spans[index as usize].ctxt)
+            }
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 656deebb5d0..3247d5e46ef 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -387,6 +387,7 @@ symbols! {
         asm_sym,
         asm_unwind,
         assert,
+        assert_eq,
         assert_eq_macro,
         assert_inhabited,
         assert_macro,
@@ -1639,6 +1640,7 @@ symbols! {
         unsafe_block_in_unsafe_fn,
         unsafe_cell,
         unsafe_cell_from_mut,
+        unsafe_cell_raw_get,
         unsafe_no_drop_flag,
         unsafe_pin_internals,
         unsize,
diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs
index a980ee8d9e0..cb88fa89058 100644
--- a/compiler/rustc_span/src/tests.rs
+++ b/compiler/rustc_span/src/tests.rs
@@ -7,9 +7,7 @@ fn test_lookup_line() {
         SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256)
             .unwrap();
     sf.start_pos = BytePos(3);
-    sf.lines(|lines| {
-        assert_eq!(lines, &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)])
-    });
+    assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]);
 
     assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0));
     assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0));
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 8d573def9bb..1a4a46ceb40 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -36,7 +36,10 @@ pub enum PassMode {
     Ignore,
     /// Pass the argument directly.
     ///
-    /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases `Aggregate`.
+    /// The argument has a layout abi of `Scalar` or `Vector`.
+    /// Unfortunately due to past mistakes, in rare cases on wasm, it can also be `Aggregate`.
+    /// This is bad since it leaks LLVM implementation details into the ABI.
+    /// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
     Direct(ArgAttributes),
     /// Pass a pair's elements directly in two arguments.
     ///
@@ -55,6 +58,29 @@ pub enum PassMode {
     Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
 }
 
+impl PassMode {
+    /// Checks if these two `PassMode` are equal enough to be considered "the same for all
+    /// function call ABIs". However, the `Layout` can also impact ABI decisions,
+    /// so that needs to be compared as well!
+    pub fn eq_abi(&self, other: &Self) -> bool {
+        match (self, other) {
+            (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type
+            (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2),
+            (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2),
+            (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1.eq_abi(c2) && pad1 == pad2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
+            ) => a1.eq_abi(a2) && s1 == s2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 },
+            ) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2,
+            _ => false,
+        }
+    }
+}
+
 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
 // of this module
 pub use attr_impl::ArgAttribute;
@@ -127,6 +153,24 @@ impl ArgAttributes {
     pub fn contains(&self, attr: ArgAttribute) -> bool {
         self.regular.contains(attr)
     }
+
+    /// Checks if these two `ArgAttributes` are equal enough to be considered "the same for all
+    /// function call ABIs".
+    pub fn eq_abi(&self, other: &Self) -> bool {
+        // There's only one regular attribute that matters for the call ABI: InReg.
+        // Everything else is things like noalias, dereferenceable, nonnull, ...
+        // (This also applies to pointee_size, pointee_align.)
+        if self.regular.contains(ArgAttribute::InReg) != other.regular.contains(ArgAttribute::InReg)
+        {
+            return false;
+        }
+        // We also compare the sign extension mode -- this could let the callee make assumptions
+        // about bits that conceptually were not even passed.
+        if self.arg_ext != other.arg_ext {
+            return false;
+        }
+        return true;
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
@@ -272,6 +316,14 @@ impl CastTarget {
                 acc.max(align)
             })
     }
+
+    /// Checks if these two `CastTarget` are equal enough to be considered "the same for all
+    /// function call ABIs".
+    pub fn eq_abi(&self, other: &Self) -> bool {
+        let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self;
+        let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other;
+        prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r)
+    }
 }
 
 /// Return value from the `homogeneous_aggregate` test function.
@@ -330,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
     /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
     /// special-cased in ABIs.
     ///
-    /// Note: We generally ignore fields of zero-sized type when computing
-    /// this value (see #56877).
+    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
     ///
     /// This is public so that it can be used in unit tests, but
     /// should generally only be relevant to the ABI details of
@@ -389,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
                         let mut total = start;
 
                         for i in 0..layout.fields.count() {
+                            let field = layout.field(cx, i);
+                            if field.is_1zst() {
+                                // No data here and no impact on layout, can be ignored.
+                                // (We might be able to also ignore all aligned ZST but that's less clear.)
+                                continue;
+                            }
+
                             if !is_union && total != layout.fields.offset(i) {
+                                // This field isn't just after the previous one we considered, abort.
                                 return Err(Heterogeneous);
                             }
 
-                            let field = layout.field(cx, i);
-
                             result = result.merge(field.homogeneous_aggregate(cx)?)?;
 
                             // Keep track of the offset (without padding).
@@ -465,6 +522,7 @@ pub struct ArgAbi<'a, Ty> {
 }
 
 impl<'a, Ty> ArgAbi<'a, Ty> {
+    /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`.
     pub fn new(
         cx: &impl HasDataLayout,
         layout: TyAndLayout<'a, Ty>,
@@ -478,6 +536,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
                 scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)),
             ),
             Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
+            // The `Aggregate` ABI should always be adjusted later.
             Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
         };
         ArgAbi { layout, mode }
@@ -570,6 +629,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     pub fn is_ignore(&self) -> bool {
         matches!(self.mode, PassMode::Ignore)
     }
+
+    /// Checks if these two `ArgAbi` are equal enough to be considered "the same for all
+    /// function call ABIs".
+    pub fn eq_abi(&self, other: &Self) -> bool {
+        // Ideally we'd just compare the `mode`, but that is not enough -- for some modes LLVM will look
+        // at the type.
+        self.layout.eq_abi(&other.layout) && self.mode.eq_abi(&other.mode)
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs
index 0eb2309ecb2..796b752ff9d 100644
--- a/compiler/rustc_target/src/abi/call/wasm.rs
+++ b/compiler/rustc_target/src/abi/call/wasm.rs
@@ -61,6 +61,10 @@ where
 /// The purpose of this ABI is for matching the WebAssembly standard. This
 /// intentionally diverges from the C ABI and is specifically crafted to take
 /// advantage of LLVM's support of multiple returns in WebAssembly.
+///
+/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM
+/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change.
+/// Also see <https://github.com/rust-lang/rust/issues/115666>.
 pub fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
     if !fn_abi.ret.is_ignore() {
         classify_ret(&mut fn_abi.ret);
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 2a09a7dcd89..2db24c43734 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -40,5 +40,7 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
     .label = expected value here
     .note = eg `#[rustc_on_unimplemented(message="foo")]`
 
+trait_selection_trait_has_no_impls = this trait has no implementations, consider adding one
+
 trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead
 trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index a9d182abfb7..77c0f9f090c 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -365,6 +365,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
                 // FIXME: we should fold this ty eventually
                 CanonicalVarKind::Const(ui, c.ty())
             }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
+                bug!("effect var has no universe")
+            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
                 bug!("fresh var during canonicalization: {c:?}")
             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 746a38f956a..e4f5c4003c9 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -3009,10 +3009,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // Try to report a help message
         if is_fn_trait
             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
-            obligation.param_env,
-            trait_ref.self_ty(),
-            trait_predicate.skip_binder().polarity,
-        )
+                obligation.param_env,
+                trait_ref.self_ty(),
+                trait_predicate.skip_binder().polarity,
+            )
         {
             self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
         } else if !trait_ref.has_non_region_infer()
@@ -3031,6 +3031,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 None,
                 obligation.cause.body_id,
             );
+        } else if trait_ref.def_id().is_local()
+            && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
+            && !self.tcx.trait_is_auto(trait_ref.def_id())
+            && !self.tcx.trait_is_alias(trait_ref.def_id())
+        {
+            err.span_help(
+                self.tcx.def_span(trait_ref.def_id()),
+                crate::fluent_generated::trait_selection_trait_has_no_impls,
+            );
         } else if !suggested && !unsatisfied_const {
             // Can't show anything else useful, try to find similar impls.
             let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
@@ -3041,7 +3050,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 err,
                 true,
             ) {
-                self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+                self.report_similar_impl_candidates_for_root_obligation(
+                    &obligation,
+                    *trait_predicate,
+                    body_def_id,
+                    err,
+                );
             }
 
             self.suggest_convert_to_slice(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 611ec6b00ef..d6ac7208715 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -838,7 +838,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         obligation.param_env,
                         real_trait_pred_and_base_ty,
                     );
-                    if self.predicate_may_hold(&obligation) {
+                    let sized_obligation = Obligation::new(
+                        self.tcx,
+                        obligation.cause.clone(),
+                        obligation.param_env,
+                        ty::TraitRef::from_lang_item(
+                            self.tcx,
+                            hir::LangItem::Sized,
+                            obligation.cause.span,
+                            [base_ty],
+                        ),
+                    );
+                    if self.predicate_may_hold(&obligation)
+                        && self.predicate_must_hold_modulo_regions(&sized_obligation)
+                    {
                         let call_node = self.tcx.hir().get(*call_hir_id);
                         let msg = "consider dereferencing here";
                         let is_receiver = matches!(
@@ -1792,7 +1805,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         );
                     } else {
                         err.note(format!(
-                            "`{}` is implemented for `{:?}`, but not for `{:?}`",
+                            "`{}` is implemented for `{}`, but not for `{}`",
                             trait_pred.print_modifiers_and_trait_path(),
                             suggested_ty,
                             trait_pred.skip_binder().self_ty(),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 3ebf1246a41..f1779451bc5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,6 +6,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::GenericArgsRef;
@@ -623,9 +624,27 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     }
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
-                ty::PredicateKind::AliasRelate(..) => {
-                    bug!("AliasRelate is only used for new solver")
+                ty::PredicateKind::AliasRelate(..)
+                    if matches!(self.selcx.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
+                {
+                    ProcessResult::Unchanged
                 }
+                ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
+                    ty::AliasRelationDirection::Equate => match self
+                        .selcx
+                        .infcx
+                        .at(&obligation.cause, obligation.param_env)
+                        .eq(DefineOpaqueTypes::Yes, a, b)
+                    {
+                        Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
+                        Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
+                            SelectionError::Unimplemented,
+                        )),
+                    },
+                    ty::AliasRelationDirection::Subtype => {
+                        bug!("AliasRelate with subtyping is only used for new solver")
+                    }
+                },
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
                         DefineOpaqueTypes::No,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7e4d926dc8d..0d84fee8309 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -37,6 +37,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::relate::TypeRelation;
@@ -1000,9 +1001,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
                     }
                 }
-                ty::PredicateKind::AliasRelate(..) => {
-                    bug!("AliasRelate is only used for new solver")
+                ty::PredicateKind::AliasRelate(..)
+                    if matches!(self.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
+                {
+                    Ok(EvaluatedToAmbig)
                 }
+                ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
+                    ty::AliasRelationDirection::Equate => match self
+                        .infcx
+                        .at(&obligation.cause, obligation.param_env)
+                        .eq(DefineOpaqueTypes::Yes, a, b)
+                    {
+                        Ok(inf_ok) => self.evaluate_predicates_recursively(
+                            previous_stack,
+                            inf_ok.into_obligations(),
+                        ),
+                        Err(_) => Ok(EvaluatedToErr),
+                    },
+                    ty::AliasRelationDirection::Subtype => {
+                        bug!("AliasRelate subtyping is only used for new solver")
+                    }
+                },
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.infcx.at(&obligation.cause, obligation.param_env).eq(
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 802391f1aad..3ffe670d87a 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -520,6 +520,8 @@ fn fn_abi_adjust_for_abi<'tcx>(
 
                 _ => return,
             }
+            // `Aggregate` ABI must be adjusted to ensure that ABI-compatible Rust types are passed
+            // the same way.
 
             let size = arg.layout.size;
             if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index ed7b3496894..904f1b38740 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -7,6 +7,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
     self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt,
 };
@@ -937,7 +938,7 @@ fn record_layout_for_printing_outlined<'tcx>(
 
     // (delay format until we actually need it)
     let record = |kind, packed, opt_discr_size, variants| {
-        let type_desc = format!("{:?}", layout.ty);
+        let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty));
         cx.tcx.sess.code_stats.record_type_size(
             kind,
             type_desc,
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 34fd31e49e1..1fc5d9359a4 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -19,13 +19,32 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
     // needs drop.
     let adt_has_dtor =
         |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);
-    let res =
-        drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some();
+    let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false)
+        .filter(filter_array_elements(tcx, query.param_env))
+        .next()
+        .is_some();
 
     debug!("needs_drop_raw({:?}) = {:?}", query, res);
     res
 }
 
+/// HACK: in order to not mistakenly assume that `[PhantomData<T>; N]` requires drop glue
+/// we check the element type for drop glue. The correct fix would be looking at the
+/// entirety of the code around `needs_drop_components` and this file and come up with
+/// logic that is easier to follow while not repeating any checks that may thus diverge.
+fn filter_array_elements<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> impl Fn(&Result<Ty<'tcx>, AlwaysRequiresDrop>) -> bool {
+    move |ty| match ty {
+        Ok(ty) => match *ty.kind() {
+            ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)),
+            _ => true,
+        },
+        Err(AlwaysRequiresDrop) => true,
+    }
+}
+
 fn has_significant_drop_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
@@ -37,6 +56,7 @@ fn has_significant_drop_raw<'tcx>(
         adt_consider_insignificant_dtor(tcx),
         true,
     )
+    .filter(filter_array_elements(tcx, query.param_env))
     .next()
     .is_some();
     debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index e0abc7f04f5..e348591ebba 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -574,16 +574,16 @@ rustc_index::newtype_index! {
     pub struct TyVid {}
 }
 
-/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
-pub struct IntVid {
-    pub index: u32,
+rustc_index::newtype_index! {
+    /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
+    #[debug_format = "?{}i"]
+    pub struct IntVid {}
 }
 
-/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
-pub struct FloatVid {
-    pub index: u32,
+rustc_index::newtype_index! {
+    /// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
+    #[debug_format = "?{}f"]
+    pub struct FloatVid {}
 }
 
 /// A placeholder for a type that hasn't been inferred yet.
@@ -645,11 +645,11 @@ impl UnifyKey for IntVid {
     type Value = Option<IntVarValue>;
     #[inline] // make this function eligible for inlining - it is quite hot.
     fn index(&self) -> u32 {
-        self.index
+        self.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> IntVid {
-        IntVid { index: i }
+        IntVid::from_u32(i)
     }
     fn tag() -> &'static str {
         "IntVid"
@@ -662,11 +662,11 @@ impl UnifyKey for FloatVid {
     type Value = Option<FloatVarValue>;
     #[inline]
     fn index(&self) -> u32 {
-        self.index
+        self.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> FloatVid {
-        FloatVid { index: i }
+        FloatVid::from_u32(i)
     }
     fn tag() -> &'static str {
         "FloatVid"
@@ -770,18 +770,6 @@ impl fmt::Debug for FloatVarValue {
     }
 }
 
-impl fmt::Debug for IntVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}i", self.index)
-    }
-}
-
-impl fmt::Debug for FloatVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}f", self.index)
-    }
-}
-
 impl fmt::Debug for Variance {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(match *self {
diff --git a/config.example.toml b/config.example.toml
index 5c4bee87553..2e0558c3f1b 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -294,9 +294,11 @@ changelog-seen = 2
 
 # 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"
-# which are used to install Rust and Cargo together. This is disabled by
-# default. The `tools` option (immediately below) specifies which tools should
-# be built if `extended = true`.
+# which are used to install Rust and Cargo together.
+# The `tools` (check `config.example.toml` to see its default value) option specifies
+# which tools should be built if `extended = true`.
+#
+# This is disabled by default.
 #extended = false
 
 # Set of tools to be included in the installation.
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 20dce6516bf..e6c793a6516 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -2165,6 +2165,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[inline(always)]
     #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
     #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
+    #[rustc_diagnostic_item = "unsafe_cell_raw_get"]
     pub const fn raw_get(this: *const Self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
         // #[repr(transparent)]. This exploits std's special status, there is
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 515b8d20ead..4ac956e7b76 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -9,8 +9,58 @@ use crate::unicode::{self, conversions};
 use super::*;
 
 impl char {
+    /// The lowest valid code point a `char` can have, `'\0'`.
+    ///
+    /// Unlike integer types, `char` actually has a gap in the middle,
+    /// meaning that the range of possible `char`s is smaller than you
+    /// might expect. Ranges of `char` will automatically hop this gap
+    /// for you:
+    ///
+    /// ```
+    /// #![feature(char_min)]
+    /// let dist = u32::from(char::MAX) - u32::from(char::MIN);
+    /// let size = (char::MIN..=char::MAX).count() as u32;
+    /// assert!(size < dist);
+    /// ```
+    ///
+    /// Despite this gap, the `MIN` and [`MAX`] values can be used as bounds for
+    /// all `char` values.
+    ///
+    /// [`MAX`]: char::MAX
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(char_min)]
+    /// # fn something_which_returns_char() -> char { 'a' }
+    /// let c: char = something_which_returns_char();
+    /// assert!(char::MIN <= c);
+    ///
+    /// let value_at_min = u32::from(char::MIN);
+    /// assert_eq!(char::from_u32(value_at_min), Some('\0'));
+    /// ```
+    #[unstable(feature = "char_min", issue = "114298")]
+    pub const MIN: char = '\0';
+
     /// The highest valid code point a `char` can have, `'\u{10FFFF}'`.
     ///
+    /// Unlike integer types, `char` actually has a gap in the middle,
+    /// meaning that the range of possible `char`s is smaller than you
+    /// might expect. Ranges of `char` will automatically hop this gap
+    /// for you:
+    ///
+    /// ```
+    /// #![feature(char_min)]
+    /// let dist = u32::from(char::MAX) - u32::from(char::MIN);
+    /// let size = (char::MIN..=char::MAX).count() as u32;
+    /// assert!(size < dist);
+    /// ```
+    ///
+    /// Despite this gap, the [`MIN`] and `MAX` values can be used as bounds for
+    /// all `char` values.
+    ///
+    /// [`MIN`]: char::MIN
+    ///
     /// # Examples
     ///
     /// ```
@@ -18,7 +68,7 @@ impl char {
     /// let c: char = something_which_returns_char();
     /// assert!(c <= char::MAX);
     ///
-    /// let value_at_max = char::MAX as u32;
+    /// let value_at_max = u32::from(char::MAX);
     /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}'));
     /// assert_eq!(char::from_u32(value_at_max + 1), None);
     /// ```
diff --git a/library/core/src/error.md b/library/core/src/error.md
index 7771b8adc92..a5deb71e6b8 100644
--- a/library/core/src/error.md
+++ b/library/core/src/error.md
@@ -37,7 +37,7 @@ responsibilities they cover:
 The panic and error systems are not entirely distinct. Often times errors
 that are anticipated runtime failures in an API might instead represent bugs
 to a caller. For these situations the standard library provides APIs for
-constructing panics with an `Error` as it's source.
+constructing panics with an `Error` as its source.
 
 * [`Result::unwrap`]
 * [`Result::expect`]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 732fcce0f29..bc701d97bbb 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1126,6 +1126,11 @@ impl<T> fmt::Debug for Discriminant<T> {
 ///
 /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
 ///
+/// The value of a [`Discriminant<T>`] is independent of any *lifetimes* in `T`. As such, reading
+/// or writing a `Discriminant<Foo<'a>>` as a `Discriminant<Foo<'b>>` (whether via [`transmute`] or
+/// otherwise) is always sound. Note that this is **not** true for other kinds of generic
+/// parameters; `Discriminant<Foo<A>>` and `Discriminant<Foo<B>>` might be incompatible.
+///
 /// # Examples
 ///
 /// This can be used to compare enums that carry data, while disregarding
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 9dbb3f9d322..6d623b82c1c 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -109,7 +109,7 @@ impl<T: ?Sized> *mut T {
     /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit
     /// coercion.
     ///
-    /// [`cast_mut`]: #method.cast_mut
+    /// [`cast_mut`]: pointer::cast_mut
     #[stable(feature = "ptr_const_cast", since = "1.65.0")]
     #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     #[rustc_diagnostic_item = "ptr_cast_const"]
@@ -121,7 +121,7 @@ impl<T: ?Sized> *mut T {
     /// Casts a pointer to its raw bits.
     ///
     /// This is equivalent to `as usize`, but is more specific to enhance readability.
-    /// The inverse method is [`from_bits`](#method.from_bits-1).
+    /// The inverse method is [`from_bits`](pointer#method.from_bits-1).
     ///
     /// In particular, `*p as usize` and `p as usize` will both compile for
     /// pointers to numeric types but do very different things, so using this
@@ -157,7 +157,7 @@ impl<T: ?Sized> *mut T {
     /// Creates a pointer from its raw bits.
     ///
     /// This is equivalent to `as *mut T`, but is more specific to enhance readability.
-    /// The inverse method is [`to_bits`](#method.to_bits-1).
+    /// The inverse method is [`to_bits`](pointer#method.to_bits-1).
     ///
     /// # Examples
     ///
@@ -307,7 +307,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// For the mutable counterpart see [`as_mut`].
     ///
-    /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+    /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
     /// [`as_mut`]: #method.as_mut
     ///
     /// # Safety
@@ -373,7 +373,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// For the mutable counterpart see [`as_uninit_mut`].
     ///
-    /// [`as_ref`]: #method.as_ref-1
+    /// [`as_ref`]: pointer#method.as_ref-1
     /// [`as_uninit_mut`]: #method.as_uninit_mut
     ///
     /// # Safety
@@ -628,7 +628,7 @@ impl<T: ?Sized> *mut T {
     /// For the shared counterpart see [`as_ref`].
     ///
     /// [`as_uninit_mut`]: #method.as_uninit_mut
-    /// [`as_ref`]: #method.as_ref-1
+    /// [`as_ref`]: pointer#method.as_ref-1
     ///
     /// # Safety
     ///
@@ -693,7 +693,7 @@ impl<T: ?Sized> *mut T {
     /// For the shared counterpart see [`as_uninit_ref`].
     ///
     /// [`as_mut`]: #method.as_mut
-    /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+    /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
     ///
     /// # Safety
     ///
@@ -783,7 +783,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// This function is the inverse of [`offset`].
     ///
-    /// [`offset`]: #method.offset-1
+    /// [`offset`]: pointer#method.offset-1
     ///
     /// # Safety
     ///
@@ -2064,7 +2064,7 @@ impl<T> *mut [T] {
     ///
     /// For the mutable counterpart see [`as_uninit_slice_mut`].
     ///
-    /// [`as_ref`]: #method.as_ref-1
+    /// [`as_ref`]: pointer#method.as_ref-1
     /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut
     ///
     /// # Safety
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index ea10bb8636c..4eb0d92b38b 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -527,8 +527,6 @@ impl Error {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_error_other)]
-    ///
     /// use std::io::Error;
     ///
     /// // errors can be created from strings
@@ -537,7 +535,7 @@ impl Error {
     /// // errors can also be created from other errors
     /// let custom_error2 = Error::other(custom_error);
     /// ```
-    #[unstable(feature = "io_error_other", issue = "91946")]
+    #[stable(feature = "io_error_other", since = "CURRENT_RUSTC_VERSION")]
     pub fn other<E>(error: E) -> Error
     where
         E: Into<Box<dyn error::Error + Send + Sync>>,
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 7380b45b00f..762a1e9b408 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1501,6 +1501,66 @@ impl From<fs::File> for Stdio {
     }
 }
 
+#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")]
+impl From<io::Stdout> for Stdio {
+    /// Redirect command stdout/stderr to our stdout
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(exit_status_error)]
+    /// use std::io;
+    /// use std::process::Command;
+    ///
+    /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+    /// let output = Command::new("whoami")
+    // "whoami" is a command which exists on both Unix and Windows,
+    // and which succeeds, producing some stdout output but no stderr.
+    ///     .stdout(io::stdout())
+    ///     .output()?;
+    /// output.status.exit_ok()?;
+    /// assert!(output.stdout.is_empty());
+    /// # Ok(())
+    /// # }
+    /// #
+    /// # if cfg!(unix) {
+    /// #     test().unwrap();
+    /// # }
+    /// ```
+    fn from(inherit: io::Stdout) -> Stdio {
+        Stdio::from_inner(inherit.into())
+    }
+}
+
+#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")]
+impl From<io::Stderr> for Stdio {
+    /// Redirect command stdout/stderr to our stderr
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(exit_status_error)]
+    /// use std::io;
+    /// use std::process::Command;
+    ///
+    /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+    /// let output = Command::new("whoami")
+    ///     .stdout(io::stderr())
+    ///     .output()?;
+    /// output.status.exit_ok()?;
+    /// assert!(output.stdout.is_empty());
+    /// # Ok(())
+    /// # }
+    /// #
+    /// # if cfg!(unix) {
+    /// #     test().unwrap();
+    /// # }
+    /// ```
+    fn from(inherit: io::Stderr) -> Stdio {
+        Stdio::from_inner(inherit.into())
+    }
+}
+
 /// Describes the result of a process after it has terminated.
 ///
 /// This `struct` is used to represent the exit status or other termination of a child process.
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index e7d1533f122..f729da44774 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -13,7 +13,7 @@ use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::IntoInner;
+use crate::sys_common::{FromInner, IntoInner};
 
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
@@ -150,6 +150,7 @@ pub enum Stdio {
     Null,
     MakePipe,
     Fd(FileDesc),
+    StaticFd(BorrowedFd<'static>),
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -463,6 +464,11 @@ impl Stdio {
                 }
             }
 
+            Stdio::StaticFd(fd) => {
+                let fd = FileDesc::from_inner(fd.try_clone_to_owned()?);
+                Ok((ChildStdio::Owned(fd), None))
+            }
+
             Stdio::MakePipe => {
                 let (reader, writer) = pipe::anon_pipe()?;
                 let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
@@ -497,6 +503,28 @@ impl From<File> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        // This ought really to be is Stdio::StaticFd(input_argument.as_fd()).
+        // But AsFd::as_fd takes its argument by reference, and yields
+        // a bounded lifetime, so it's no use here. There is no AsStaticFd.
+        //
+        // Additionally AsFd is only implemented for the *locked* versions.
+        // We don't want to lock them here.  (The implications of not locking
+        // are the same as those for process::Stdio::inherit().)
+        //
+        // Arguably the hypothetical AsStaticFd and AsFd<'static>
+        // should be implemented for io::Stdout, not just for StdoutLocked.
+        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) })
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) })
+    }
+}
+
 impl ChildStdio {
     pub fn fd(&self) -> Option<c_int> {
         match *self {
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 4f2d9cf3655..7c242d4d334 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -182,6 +182,9 @@ impl Thread {
         }
 
         if let Some(f) = pthread_setname_np.get() {
+            #[cfg(target_os = "nto")]
+            let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name);
+
             let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
             debug_assert_eq!(res, 0);
         }
@@ -290,6 +293,7 @@ impl Drop for Thread {
     target_os = "ios",
     target_os = "tvos",
     target_os = "watchos",
+    target_os = "nto",
 ))]
 fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
     let mut result = [0; MAX_WITH_NUL];
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 77b675aaa4e..a639afcc674 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -27,6 +27,8 @@ pub struct StdioPipes {
     pub stderr: Option<AnonPipe>,
 }
 
+// FIXME: This should be a unit struct, so we can always construct it
+// The value here should be never used, since we cannot spawn processes.
 pub enum Stdio {
     Inherit,
     Null,
@@ -87,8 +89,26 @@ impl From<AnonPipe> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
+        panic!("unsupported")
+    }
+}
+
 impl From<File> for Stdio {
     fn from(_file: File) -> Stdio {
+        // FIXME: This is wrong.
+        // Instead, the Stdio we have here should be a unit struct.
         panic!("unsupported")
     }
 }
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 84a75d21305..cd5bf7f1538 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -172,6 +172,7 @@ pub struct Command {
 
 pub enum Stdio {
     Inherit,
+    InheritSpecific { from_stdio_id: c::DWORD },
     Null,
     MakePipe,
     Pipe(AnonPipe),
@@ -555,17 +556,19 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> {
 
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
-        match *self {
-            Stdio::Inherit => match stdio::get_handle(stdio_id) {
-                Ok(io) => unsafe {
-                    let io = Handle::from_raw_handle(io);
-                    let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
-                    io.into_raw_handle();
-                    ret
-                },
-                // If no stdio handle is available, then propagate the null value.
-                Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+        let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) {
+            Ok(io) => unsafe {
+                let io = Handle::from_raw_handle(io);
+                let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
+                io.into_raw_handle();
+                ret
             },
+            // If no stdio handle is available, then propagate the null value.
+            Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+        };
+        match *self {
+            Stdio::Inherit => use_stdio_id(stdio_id),
+            Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id),
 
             Stdio::MakePipe => {
                 let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
@@ -613,6 +616,18 @@ impl From<File> for Stdio {
     }
 }
 
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE }
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Processes
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/stdarch b/library/stdarch
-Subproject d77878b7299dd7e286799a6e8447048b65d2a86
+Subproject 6100854c4b360f84da5ab25e7c75cb2080667dd
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index a24a6a4636d..91fa5ec6633 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -302,8 +302,10 @@ impl StepDescription {
         }
     }
 
-    fn maybe_run(&self, builder: &Builder<'_>, pathsets: Vec<PathSet>) {
-        if pathsets.iter().any(|set| self.is_excluded(builder, set)) {
+    fn maybe_run(&self, builder: &Builder<'_>, mut pathsets: Vec<PathSet>) {
+        pathsets.retain(|set| !self.is_excluded(builder, set));
+
+        if pathsets.is_empty() {
             return;
         }
 
@@ -735,6 +737,7 @@ impl<'a> Builder<'a> {
                 test::Incremental,
                 test::Debuginfo,
                 test::UiFullDeps,
+                test::CodegenCranelift,
                 test::Rustdoc,
                 test::RunCoverageRustdoc,
                 test::Pretty,
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 43b4a34fe5b..80e66622e8b 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -136,9 +136,9 @@ fn test_exclude_kind() {
     let mut config = configure("test", &["A"], &["A"]);
     // Ensure our test is valid, and `test::Rustc` would be run without the exclude.
     assert!(run_build(&[], config.clone()).contains::<test::CrateLibrustc>());
-    // Ensure tests for rustc are skipped.
+    // Ensure tests for rustc are not skipped.
     config.skip = vec![path.clone()];
-    assert!(!run_build(&[], config.clone()).contains::<test::CrateLibrustc>());
+    assert!(run_build(&[], config.clone()).contains::<test::CrateLibrustc>());
     // Ensure builds for rustc are not skipped.
     assert!(run_build(&[], config).contains::<compile::Rustc>());
 }
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index d658be0b8eb..11f2762f766 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -127,8 +127,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         Err(_) => false,
     };
 
-    let mut paths = paths.to_vec();
-
     if git_available {
         let in_working_tree = match build
             .config
@@ -201,8 +199,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                             "WARN: Something went wrong when running git commands:\n{err}\n\
                             Falling back to formatting all files."
                         );
-                        // Something went wrong when getting the version. Just format all the files.
-                        paths.push(".".into());
                     }
                 }
             }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 4396bbc51a3..671d25484d0 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1019,7 +1019,7 @@ impl Build {
 
     fn info(&self, msg: &str) {
         match self.config.dry_run {
-            DryRun::SelfCheck => return,
+            DryRun::SelfCheck => (),
             DryRun::Disabled | DryRun::UserSelected => {
                 println!("{msg}");
             }
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 07502e0e9dd..aefed501513 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -598,9 +598,9 @@ fn configure_cmake(
         } else if target.contains("linux") {
             cfg.define("CMAKE_SYSTEM_NAME", "Linux");
         } else {
-            builder.info(
+            builder.info(&format!(
                 "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail",
-            );
+            ));
         }
 
         // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index d78e0deda69..35e2e98e08e 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -2967,3 +2967,129 @@ impl Step for TestHelpers {
             .compile("rust_test_helpers");
     }
 }
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CodegenCranelift {
+    compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl Step for CodegenCranelift {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.paths(&["compiler/rustc_codegen_cranelift"])
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        let builder = run.builder;
+        let host = run.build_triple();
+        let compiler = run.builder.compiler_for(run.builder.top_stage, host, host);
+
+        if builder.doc_tests == DocTests::Only {
+            return;
+        }
+
+        let triple = run.target.triple;
+        let target_supported = if triple.contains("linux") {
+            triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x")
+        } else if triple.contains("darwin") || triple.contains("windows") {
+            triple.contains("x86_64")
+        } else {
+            false
+        };
+        if !target_supported {
+            builder.info("target not supported by rustc_codegen_cranelift. skipping");
+            return;
+        }
+
+        if builder.remote_tested(run.target) {
+            builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping");
+            return;
+        }
+
+        if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) {
+            builder.info("cranelift not in rust.codegen-backends. skipping");
+            return;
+        }
+
+        builder.ensure(CodegenCranelift { compiler, target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let compiler = self.compiler;
+        let target = self.target;
+
+        builder.ensure(compile::Std::new(compiler, target));
+
+        // If we're not doing a full bootstrap but we're testing a stage2
+        // version of libstd, then what we're actually testing is the libstd
+        // produced in stage1. Reflect that here by updating the compiler that
+        // we're working with automatically.
+        let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
+
+        let build_cargo = || {
+            let mut cargo = builder.cargo(
+                compiler,
+                Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
+                SourceType::InTree,
+                target,
+                "run",
+            );
+            cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
+            cargo
+                .arg("--manifest-path")
+                .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
+            compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
+
+            // Avoid incremental cache issues when changing rustc
+            cargo.env("CARGO_BUILD_INCREMENTAL", "false");
+
+            cargo
+        };
+
+        builder.info(&format!(
+            "{} cranelift stage{} ({} -> {})",
+            Kind::Test.description(),
+            compiler.stage,
+            &compiler.host,
+            target
+        ));
+        let _time = util::timeit(&builder);
+
+        // FIXME handle vendoring for source tarballs before removing the --skip-test below
+        let download_dir = builder.out.join("cg_clif_download");
+
+        /*
+        let mut prepare_cargo = build_cargo();
+        prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir);
+        #[allow(deprecated)]
+        builder.config.try_run(&mut prepare_cargo.into()).unwrap();
+        */
+
+        let mut cargo = build_cargo();
+        cargo
+            .arg("--")
+            .arg("test")
+            .arg("--download-dir")
+            .arg(&download_dir)
+            .arg("--out-dir")
+            .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif"))
+            .arg("--no-unstable-features")
+            .arg("--use-backend")
+            .arg("cranelift")
+            // Avoid having to vendor the standard library dependencies
+            .arg("--sysroot")
+            .arg("llvm")
+            // These tests depend on crates that are not yet vendored
+            // FIXME remove once vendoring is handled
+            .arg("--skip-test")
+            .arg("testsuite.extended_sysroot");
+        cargo.args(builder.config.test_args());
+
+        #[allow(deprecated)]
+        builder.config.try_run(&mut cargo.into()).unwrap();
+    }
+}
diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh
index 7dae90f4403..689fe52863e 100755
--- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 7018e24d8fe248596819d2e884761676f3542a04
+git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
index 45174e708dc..4b0d360686f 100755
--- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 7018e24d8fe248596819d2e884761676f3542a04
+git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile
index 02b4664eb55..0d0f1edd003 100644
--- a/src/ci/docker/host-x86_64/wasm32/Dockerfile
+++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile
@@ -58,5 +58,6 @@ ENV NO_CHANGE_USER=1
 RUN chown 10719 -R /emsdk-portable/
 
 # Exclude library/alloc due to OOM in benches.
+# FIXME: Fix std tests
 ENV SCRIPT python3 ../x.py test --stage 2 --host='' --target $TARGETS \
-    --skip library/alloc
+    --skip library/alloc --skip library/std
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b8cb758bf40..98f2cdac5dc 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -123,6 +123,9 @@ else
 
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
 
+  # Test the Cranelift backend in on CI, but don't ship it.
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift"
+
   # We enable this for non-dist builders, since those aren't trying to produce
   # fresh binaries. We currently don't entirely support distributing a fresh
   # copy of the compiler (including llvm tools, etc.) if we haven't actually
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 2751bdcef125468ea2ee006c11992cd1405aebe
+Subproject 34fca48ed284525b2f124bf93c51af36d668549
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 388750b081c0893c275044d37203f97709e058b
+Subproject e3f3af69dce71cd37a785bccb7e58449197d940
diff --git a/src/doc/reference b/src/doc/reference
-Subproject d43038932adeb16ada80e206d4c073d85129810
+Subproject ee7c676fd6e287459cb407337652412c990686c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 07e0df2f006e59d171c6bf3cafa9d61dbeb520d
+Subproject c954202c1e1720cba5628f99543cc01188c7d6f
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject b123ab4754127d822ffb38349ce0fbf561f1b2f
+Subproject 08bb147d51e815b96e8db7ba4cf870f201c11ff
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 2c7c05c0c4b..4d32897cc14 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -260,6 +260,10 @@ The valid types of print values are:
   This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable
   is present in the environment, or otherwise returns the variable's parsed value.
 
+A filepath may optionally be specified for each requested information kind, in
+the format `--print KIND=PATH`, just like for `--emit`. When a path is
+specified, information will be written there instead of to stdout.
+
 [conditional compilation]: ../reference/conditional-compilation.html
 [deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 2cb0a8f3c17..269fe928754 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -181,6 +181,7 @@ target | std | notes
 `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
 `wasm32-unknown-unknown` | ✓ | WebAssembly
 `wasm32-wasi` | ✓ | WebAssembly with WASI
+[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ |  | WebAssembly with WASI Preview 1 and threads
 `x86_64-apple-ios` | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
@@ -323,7 +324,6 @@ target | std | host | notes
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7-A Linux with NEON, MUSL
-[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ |  | WebAssembly with WASI Preview 1 and threads
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md
index b3eb34de638..23b99924899 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md
@@ -1,6 +1,6 @@
 # `wasm32-wasi-preview1-threads`
 
-**Tier: 3**
+**Tier: 2**
 
 The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an
 experimental target. This target is an extension to `wasm32-wasi-preview1` target,
@@ -70,12 +70,6 @@ compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can
 reliably interoperate with C code in this mode (yet).
 
 
-This target is not a stable target. This means that there are not many engines
-which implement the `wasi-threads` feature and if they do they're likely behind a
-flag, for example:
-
-* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads`
-
 Also note that at this time the `wasm32-wasi-preview1-threads` target assumes the
 presence of other merged wasm proposals such as (with their LLVM feature flags):
 
@@ -94,6 +88,17 @@ The target intends to match the corresponding Clang target for its `"C"` ABI.
 > found it's recommended to open an issue either with rust-lang/rust or ideally
 > with LLVM itself.
 
+## Platform requirements
+
+The runtime should support the same set of APIs as any other supported wasi target for interacting with the host environment through the WASI standard. The runtime also should have implemetation of [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads).
+
+This target is not a stable target. This means that there are a few engines
+which implement the `wasi-threads` feature and if they do they're likely behind a
+flag, for example:
+
+* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads`
+* [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1
+
 ## Building the target
 
 Users need to install or built wasi-sdk since release 20.0
@@ -110,12 +115,16 @@ After that users can build this by adding it to the `target` list in
 
 ## Building Rust programs
 
-Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target.
+From Rust Nightly 1.71.1 (2023-08-03) on the artifacts are shipped pre-compiled:
+
+```text
+rustup target add wasm32-wasi-preview1-threads --toolchain nightly
+```
+
+Rust programs can be built for that target:
 
-Specify `wasi-root` as explained in the previous section and then use the `build-std`
-nightly cargo feature to build the standard library:
-```shell
-cargo +nightly build --target=wasm32-wasi-preview1-threads -Zbuild-std
+```text
+rustc --target wasm32-wasi-preview1-threads your-code.rs
 ```
 
 ## Cross-compilation
diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md
index 9deb7009cfe..cd6e29ffd66 100644
--- a/src/doc/rustdoc/src/how-to-read-rustdoc.md
+++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md
@@ -38,6 +38,22 @@ followed by a list of fields or variants for Rust types.
 Finally, the page lists associated functions and trait implementations,
 including automatic and blanket implementations that `rustdoc` knows about.
 
+### Sections
+
+<!-- FIXME: Implementations -->
+<!-- FIXME: Trait Implementations -->
+<!-- FIXME: Implementors -->
+<!-- FIXME: Auto Trait Implementations -->
+
+#### Aliased Type
+
+A type alias is expanded at compile time to its
+[aliased type](https://doc.rust-lang.org/reference/items/type-aliases.html).
+That may involve substituting some or all of the type parameters in the target
+type with types provided by the type alias definition. The Aliased Type section
+shows the result of this expansion, including the types of public fields or
+variants, which may depend on those substitutions.
+
 ### Navigation
 
 Subheadings, variants, fields, and many other things in this documentation
diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md
index 593428b8a70..8ce059cc29c 100644
--- a/src/doc/rustdoc/src/write-documentation/re-exports.md
+++ b/src/doc/rustdoc/src/write-documentation/re-exports.md
@@ -86,7 +86,7 @@ pub use self::Hidden as InlinedHidden;
 ```
 
 The same applies on re-exports themselves: if you have multiple re-exports and some of them have
-`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation:
+`#[doc(hidden)]`, then these ones (and only these) won't appear in the documentation:
 
 ```rust,ignore (inline)
 mod private_mod {
diff --git a/src/doc/unstable-book/src/compiler-flags/path-options.md b/src/doc/unstable-book/src/compiler-flags/path-options.md
deleted file mode 100644
index 0786ef1f166..00000000000
--- a/src/doc/unstable-book/src/compiler-flags/path-options.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# `--print` Options
-
-The behavior of the `--print` flag can be modified by optionally be specifying a filepath
-for each requested information kind, in the format `--print KIND=PATH`, just like for
-`--emit`. When a path is specified, information will be written there instead of to stdout.
-
-This is unstable feature, so you have to provide `-Zunstable-options` to enable it.
-
-## Examples
-
-`rustc main.rs -Z unstable-options --print cfg=cfgs.txt`
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cc86a3d7475..dd43ee03383 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use crate::clean::{
     self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
     clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
-    clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type,
+    clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes,
+    AttributesExt, ImplKind, ItemId, Type,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -289,16 +290,14 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
 
 fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::TypeAlias> {
     let predicates = cx.tcx.explicit_predicates_of(did);
-    let type_ = clean_middle_ty(
-        ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
-        cx,
-        Some(did),
-        None,
-    );
+    let ty = cx.tcx.type_of(did).instantiate_identity();
+    let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None);
+    let inner_type = clean_ty_alias_inner_type(ty, cx);
 
     Box::new(clean::TypeAlias {
         type_,
         generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
+        inner_type,
         item_type: None,
     })
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b584c32a4c7..f30384701cb 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -24,6 +24,7 @@ use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::ty::fold::TypeFolder;
+use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -541,7 +542,7 @@ fn clean_generic_param_def<'tcx>(
                 },
             )
         }
-        ty::GenericParamDefKind::Const { has_default } => (
+        ty::GenericParamDefKind::Const { has_default, .. } => (
             def.name,
             GenericParamDefKind::Const {
                 ty: Box::new(clean_middle_ty(
@@ -955,6 +956,43 @@ fn clean_ty_generics<'tcx>(
     }
 }
 
+fn clean_ty_alias_inner_type<'tcx>(
+    ty: Ty<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<TypeAliasInnerType> {
+    let ty::Adt(adt_def, args) = ty.kind() else {
+        return None;
+    };
+
+    Some(if adt_def.is_enum() {
+        let variants: rustc_index::IndexVec<_, _> = adt_def
+            .variants()
+            .iter()
+            .map(|variant| clean_variant_def_with_args(variant, args, cx))
+            .collect();
+
+        TypeAliasInnerType::Enum {
+            variants,
+            is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(),
+        }
+    } else {
+        let variant = adt_def
+            .variants()
+            .iter()
+            .next()
+            .unwrap_or_else(|| bug!("a struct or union should always have one variant def"));
+
+        let fields: Vec<_> =
+            clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect();
+
+        if adt_def.is_struct() {
+            TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields }
+        } else {
+            TypeAliasInnerType::Union { fields }
+        }
+    })
+}
+
 fn clean_proc_macro<'tcx>(
     item: &hir::Item<'tcx>,
     name: &mut Symbol,
@@ -1222,6 +1260,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
                     Box::new(TypeAlias {
                         type_: clean_ty(default, cx),
                         generics,
+                        inner_type: None,
                         item_type: Some(item_type),
                     }),
                     bounds,
@@ -1264,7 +1303,12 @@ pub(crate) fn clean_impl_item<'tcx>(
                     None,
                 );
                 AssocTypeItem(
-                    Box::new(TypeAlias { type_, generics, item_type: Some(item_type) }),
+                    Box::new(TypeAlias {
+                        type_,
+                        generics,
+                        inner_type: None,
+                        item_type: Some(item_type),
+                    }),
                     Vec::new(),
                 )
             }
@@ -1471,6 +1515,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                                 None,
                             ),
                             generics,
+                            inner_type: None,
                             item_type: None,
                         }),
                         bounds,
@@ -1490,6 +1535,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                             None,
                         ),
                         generics,
+                        inner_type: None,
                         item_type: None,
                     }),
                     // Associated types inside trait or inherent impls are not allowed to have
@@ -2363,6 +2409,83 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
     )
 }
 
+pub(crate) fn clean_variant_def_with_args<'tcx>(
+    variant: &ty::VariantDef,
+    args: &GenericArgsRef<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let discriminant = match variant.discr {
+        ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+        ty::VariantDiscr::Relative(_) => None,
+    };
+
+    use rustc_middle::traits::ObligationCause;
+    use rustc_trait_selection::infer::TyCtxtInferExt;
+    use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+
+    let infcx = cx.tcx.infer_ctxt().build();
+    let kind = match variant.ctor_kind() {
+        Some(CtorKind::Const) => VariantKind::CLike,
+        Some(CtorKind::Fn) => VariantKind::Tuple(
+            variant
+                .fields
+                .iter()
+                .map(|field| {
+                    let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args);
+
+                    // normalize the type to only show concrete types
+                    // note: we do not use try_normalize_erasing_regions since we
+                    // do care about showing the regions
+                    let ty = infcx
+                        .at(&ObligationCause::dummy(), cx.param_env)
+                        .query_normalize(ty)
+                        .map(|normalized| normalized.value)
+                        .unwrap_or(ty);
+
+                    clean_field_with_def_id(
+                        field.did,
+                        field.name,
+                        clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
+                        cx,
+                    )
+                })
+                .collect(),
+        ),
+        None => VariantKind::Struct(VariantStruct {
+            fields: variant
+                .fields
+                .iter()
+                .map(|field| {
+                    let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args);
+
+                    // normalize the type to only show concrete types
+                    // note: we do not use try_normalize_erasing_regions since we
+                    // do care about showing the regions
+                    let ty = infcx
+                        .at(&ObligationCause::dummy(), cx.param_env)
+                        .query_normalize(ty)
+                        .map(|normalized| normalized.value)
+                        .unwrap_or(ty);
+
+                    clean_field_with_def_id(
+                        field.did,
+                        field.name,
+                        clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
+                        cx,
+                    )
+                })
+                .collect(),
+        }),
+    };
+
+    Item::from_def_id_and_parts(
+        variant.def_id,
+        Some(variant.name),
+        VariantItem(Variant { kind, discriminant }),
+        cx,
+    )
+}
+
 fn clean_variant_data<'tcx>(
     variant: &hir::VariantData<'tcx>,
     disr_expr: &Option<hir::AnonConst>,
@@ -2617,7 +2740,7 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::TyAlias(hir_ty, generics) => {
                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
                 let rustdoc_ty = clean_ty(hir_ty, cx);
-                let ty = clean_middle_ty(
+                let type_ = clean_middle_ty(
                     ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
                     cx,
                     None,
@@ -2630,10 +2753,15 @@ fn clean_maybe_renamed_item<'tcx>(
                         cx.current_type_aliases.remove(&def_id);
                     }
                 }
+
+                let ty = cx.tcx.type_of(def_id).instantiate_identity();
+                let inner_type = clean_ty_alias_inner_type(ty, cx);
+
                 TypeAliasItem(Box::new(TypeAlias {
-                    type_: rustdoc_ty,
                     generics,
-                    item_type: Some(ty),
+                    inner_type,
+                    type_: rustdoc_ty,
+                    item_type: Some(type_),
                 }))
             }
             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9134d5268da..b276745f317 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -25,7 +25,9 @@ use rustc_index::IndexVec;
 use rustc_metadata::rendered_const;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt, Visibility};
-use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment};
+use rustc_resolve::rustdoc::{
+    add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments, DocFragment,
+};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -397,7 +399,7 @@ impl Item {
     }
 
     pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
-        crate::passes::span_of_attrs(&self.attrs)
+        span_of_fragments(&self.attrs.doc_strings)
             .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner()))
     }
 
@@ -2231,9 +2233,19 @@ pub(crate) struct PathSegment {
 }
 
 #[derive(Clone, Debug)]
+pub(crate) enum TypeAliasInnerType {
+    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
+    Union { fields: Vec<Item> },
+    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
+}
+
+#[derive(Clone, Debug)]
 pub(crate) struct TypeAlias {
     pub(crate) type_: Type,
     pub(crate) generics: Generics,
+    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
+    /// to be shown directly on the typedef page.
+    pub(crate) inner_type: Option<TypeAliasInnerType>,
     /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
     /// alias instead of the final type. This will always have the final type, regardless of whether
     /// `type_` came from HIR or from metadata.
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 1ce7efdfc20..974dc1c5135 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -157,6 +157,12 @@ pub(crate) struct Options {
     /// Note: this field is duplicated in `RenderOptions` because it's useful
     /// to have it in both places.
     pub(crate) unstable_features: rustc_feature::UnstableFeatures,
+
+    /// All commandline args used to invoke the compiler, with @file args fully expanded.
+    /// This will only be used within debug info, e.g. in the pdb file on windows
+    /// This is mainly useful for other tools that reads that debuginfo to figure out
+    /// how to call the compiler with the same arguments.
+    pub(crate) expanded_args: Vec<String>,
 }
 
 impl fmt::Debug for Options {
@@ -744,6 +750,7 @@ impl Options {
             json_unused_externs,
             scrape_examples_options,
             unstable_features,
+            expanded_args: args,
         };
         let render_options = RenderOptions {
             output,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index eadff37b592..7cd25ef444b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -194,6 +194,7 @@ pub(crate) fn create_config(
         describe_lints,
         lint_cap,
         scrape_examples_options,
+        expanded_args,
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
@@ -291,6 +292,7 @@ pub(crate) fn create_config(
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
+        expanded_args,
     }
 }
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 36d5adb6304..ea87268877f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -10,6 +10,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::attr::InnerAttrPolicy;
+use rustc_resolve::rustdoc::span_of_fragments;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::parse::ParseSess;
 use rustc_session::{lint, EarlyErrorHandler, Session};
@@ -33,7 +34,6 @@ use crate::clean::{types::AttributesExt, Attributes};
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
 use crate::lint::init_lints;
-use crate::passes::span_of_attrs;
 
 /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
 #[derive(Clone, Default)]
@@ -109,6 +109,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
+        expanded_args: options.expanded_args.clone(),
     };
 
     let test_args = options.test_args.clone();
@@ -1240,7 +1241,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
                 Some(&crate::html::markdown::ExtraInfo::new(
                     self.tcx,
                     def_id.to_def_id(),
-                    span_of_attrs(&attrs).unwrap_or(sp),
+                    span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
                 )),
             );
         }
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index ceba643ed5f..cf11e2d7899 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -52,10 +52,31 @@ pub(crate) trait DocFolder: Sized {
 
                 VariantItem(Variant { kind, discriminant })
             }
+            TypeAliasItem(mut typealias) => {
+                typealias.inner_type = typealias.inner_type.map(|inner_type| match inner_type {
+                    TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
+                        let variants = variants
+                            .into_iter_enumerated()
+                            .filter_map(|(_, x)| self.fold_item(x))
+                            .collect();
+
+                        TypeAliasInnerType::Enum { variants, is_non_exhaustive }
+                    }
+                    TypeAliasInnerType::Union { fields } => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        TypeAliasInnerType::Union { fields }
+                    }
+                    TypeAliasInnerType::Struct { ctor_kind, fields } => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        TypeAliasInnerType::Struct { ctor_kind, fields }
+                    }
+                });
+
+                TypeAliasItem(typealias)
+            }
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
-            | TypeAliasItem(_)
             | OpaqueTyItem(_)
             | StaticItem(_)
             | ConstantItem(_)
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 9a34e7cce8a..4c6e7dfb987 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -457,6 +457,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::StructItem(..)
             | clean::UnionItem(..)
             | clean::VariantItem(..)
+            | clean::TypeAliasItem(..)
             | clean::ImplItem(..) => {
                 self.cache.parent_stack.push(ParentStackItem::new(&item));
                 (self.fold_item_recur(item), true)
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 98cc38a10d4..b28019e3f91 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1574,7 +1574,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("crate-search-div".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
-    map.insert("mainThemeStyle".into(), 1);
     map.insert("themeStyle".into(), 1);
     map.insert("settings-menu".into(), 1);
     map.insert("help-button".into(), 1);
@@ -1610,6 +1609,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("blanket-implementations-list".into(), 1);
     map.insert("deref-methods".into(), 1);
     map.insert("layout".into(), 1);
+    map.insert("aliased-type".into(), 1);
     map
 }
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index bb1c186668c..0bc10c5e10f 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -7,8 +7,10 @@ use std::sync::mpsc::{channel, Receiver};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use rustc_span::{sym, Symbol};
@@ -22,13 +24,13 @@ use super::{
     sidebar::{sidebar_module_like, Sidebar},
     AllTypes, LinkFromSrc, StylePath,
 };
-use crate::clean::{self, types::ExternalLocation, ExternalCrate};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem};
 use crate::config::{ModuleSorting, RenderOptions};
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::formats::FormatRenderer;
+use crate::formats::{self, FormatRenderer};
 use crate::html::escape::Escape;
 use crate::html::format::{join_with_double_colon, Buffer};
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
@@ -147,6 +149,53 @@ impl SharedContext<'_> {
     pub(crate) fn edition(&self) -> Edition {
         self.tcx.sess.edition()
     }
+
+    /// Returns a list of impls on the given type, and, if it's a type alias,
+    /// other types that it aliases.
+    pub(crate) fn all_impls_for_item<'a>(
+        &'a self,
+        it: &clean::Item,
+        did: DefId,
+    ) -> Vec<&'a formats::Impl> {
+        let tcx = self.tcx;
+        let cache = &self.cache;
+        let mut saw_impls = FxHashSet::default();
+        let mut v: Vec<&formats::Impl> = cache
+            .impls
+            .get(&did)
+            .map(Vec::as_slice)
+            .unwrap_or(&[])
+            .iter()
+            .filter(|i| saw_impls.insert(i.def_id()))
+            .collect();
+        if let TypeAliasItem(ait) = &*it.kind &&
+            let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) &&
+            let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) &&
+            let Some(av) = cache.impls.get(&aliased_type_defid) &&
+            let Some(alias_def_id) = it.item_id.as_def_id()
+        {
+            // This branch of the compiler compares types structually, but does
+            // not check trait bounds. That's probably fine, since type aliases
+            // don't normally constrain on them anyway.
+            // https://github.com/rust-lang/rust/issues/21903
+            //
+            // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification.
+            // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress.
+            let aliased_ty = tcx.type_of(alias_def_id).skip_binder();
+            let reject_cx = DeepRejectCtxt {
+                treat_obligation_params: TreatParams::AsCandidateKey,
+            };
+            v.extend(av.iter().filter(|impl_| {
+                if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() {
+                    reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder())
+                        && saw_impls.insert(impl_def_id)
+                } else {
+                    false
+                }
+            }));
+        }
+        v
+    }
 }
 
 impl<'tcx> Context<'tcx> {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index aef8f1a74fb..5adbecd6d04 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1117,13 +1117,13 @@ pub(crate) fn render_all_impls(
 fn render_assoc_items<'a, 'cx: 'a>(
     cx: &'a mut Context<'cx>,
     containing_item: &'a clean::Item,
-    it: DefId,
+    did: DefId,
     what: AssocItemRender<'a>,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     let mut derefs = DefIdSet::default();
-    derefs.insert(it);
+    derefs.insert(did);
     display_fn(move |f| {
-        render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
+        render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs);
         Ok(())
     })
 }
@@ -1132,15 +1132,17 @@ fn render_assoc_items_inner(
     mut w: &mut dyn fmt::Write,
     cx: &mut Context<'_>,
     containing_item: &clean::Item,
-    it: DefId,
+    did: DefId,
     what: AssocItemRender<'_>,
     derefs: &mut DefIdSet,
 ) {
     info!("Documenting associated items of {:?}", containing_item.name);
     let shared = Rc::clone(&cx.shared);
-    let cache = &shared.cache;
-    let Some(v) = cache.impls.get(&it) else { return };
-    let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
+    let v = shared.all_impls_for_item(containing_item, did);
+    let v = v.as_slice();
+    let (non_trait, traits): (Vec<&Impl>, _) =
+        v.iter().partition(|i| i.inner_impl().trait_.is_none());
+    let mut saw_impls = FxHashSet::default();
     if !non_trait.is_empty() {
         let mut tmp_buf = Buffer::html();
         let (render_mode, id, class_html) = match what {
@@ -1169,6 +1171,9 @@ fn render_assoc_items_inner(
         };
         let mut impls_buf = Buffer::html();
         for i in &non_trait {
+            if !saw_impls.insert(i.def_id()) {
+                continue;
+            }
             render_impl(
                 &mut impls_buf,
                 cx,
@@ -1214,8 +1219,10 @@ fn render_assoc_items_inner(
 
         let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
             traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
-        let (blanket_impl, concrete): (Vec<&Impl>, _) =
-            concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
+        let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete
+            .into_iter()
+            .filter(|t| saw_impls.insert(t.def_id()))
+            .partition(|t| t.inner_impl().kind.is_blanket());
 
         render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
     }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index cb78f903462..c6751c9585e 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1237,6 +1237,75 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
 
     write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
 
+    if let Some(inner_type) = &t.inner_type {
+        write!(
+            w,
+            "<h2 id=\"aliased-type\" class=\"small-section-header\">\
+                Aliased Type<a href=\"#aliased-type\" class=\"anchor\">§</a></h2>"
+        );
+
+        match inner_type {
+            clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
+                let variants_iter = || variants.iter().filter(|i| !i.is_stripped());
+                wrap_item(w, |w| {
+                    let variants_len = variants.len();
+                    let variants_count = variants_iter().count();
+                    let has_stripped_entries = variants_len != variants_count;
+
+                    write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx));
+                    render_enum_fields(
+                        w,
+                        cx,
+                        Some(&t.generics),
+                        variants_iter(),
+                        variants_count,
+                        has_stripped_entries,
+                        *is_non_exhaustive,
+                    )
+                });
+                item_variants(w, cx, it, variants_iter());
+            }
+            clean::TypeAliasInnerType::Union { fields } => {
+                wrap_item(w, |w| {
+                    let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
+                    let has_stripped_fields = fields.len() != fields_count;
+
+                    write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx));
+                    render_struct_fields(
+                        w,
+                        Some(&t.generics),
+                        None,
+                        fields,
+                        "",
+                        true,
+                        has_stripped_fields,
+                        cx,
+                    );
+                });
+                item_fields(w, cx, it, fields, None);
+            }
+            clean::TypeAliasInnerType::Struct { ctor_kind, fields } => {
+                wrap_item(w, |w| {
+                    let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
+                    let has_stripped_fields = fields.len() != fields_count;
+
+                    write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx));
+                    render_struct_fields(
+                        w,
+                        Some(&t.generics),
+                        *ctor_kind,
+                        fields,
+                        "",
+                        true,
+                        has_stripped_fields,
+                        cx,
+                    );
+                });
+                item_fields(w, cx, it, fields, None);
+            }
+        }
+    }
+
     let def_id = it.item_id.expect_def_id();
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -1315,6 +1384,12 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
     s: &'a [clean::Item],
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     display_fn(|f| {
+        if s.iter()
+            .all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))))
+        {
+            return f.write_str("/* private fields */");
+        }
+
         for (i, ty) in s.iter().enumerate() {
             if i > 0 {
                 f.write_str(", ")?;
@@ -1332,7 +1407,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
 fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
     let tcx = cx.tcx();
     let count_variants = e.variants().count();
-    wrap_item(w, |mut w| {
+    wrap_item(w, |w| {
         render_attributes_in_code(w, it, tcx);
         write!(
             w,
@@ -1341,148 +1416,179 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
             it.name.unwrap(),
             e.generics.print(cx),
         );
-        if !print_where_clause_and_check(w, &e.generics, cx) {
-            // If there wasn't a `where` clause, we add a whitespace.
-            w.write_str(" ");
-        }
+        render_enum_fields(
+            w,
+            cx,
+            Some(&e.generics),
+            e.variants(),
+            count_variants,
+            e.has_stripped_entries(),
+            it.is_non_exhaustive(),
+        );
+    });
 
-        let variants_stripped = e.has_stripped_entries();
-        if count_variants == 0 && !variants_stripped {
-            w.write_str("{}");
-        } else {
-            w.write_str("{\n");
-            let toggle = should_hide_fields(count_variants);
-            if toggle {
-                toggle_open(&mut w, format_args!("{count_variants} variants"));
-            }
-            for v in e.variants() {
-                w.write_str("    ");
-                let name = v.name.unwrap();
-                match *v.kind {
-                    // FIXME(#101337): Show discriminant
-                    clean::VariantItem(ref var) => match var.kind {
-                        clean::VariantKind::CLike => w.write_str(name.as_str()),
-                        clean::VariantKind::Tuple(ref s) => {
-                            write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
-                        }
-                        clean::VariantKind::Struct(ref s) => {
-                            render_struct(w, v, None, None, &s.fields, "    ", false, cx);
-                        }
-                    },
-                    _ => unreachable!(),
-                }
-                w.write_str(",\n");
-            }
+    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
 
-            if variants_stripped && !it.is_non_exhaustive() {
-                w.write_str("    // some variants omitted\n");
-            }
-            if toggle {
-                toggle_close(&mut w);
+    if count_variants != 0 {
+        item_variants(w, cx, it, e.variants());
+    }
+    let def_id = it.item_id.expect_def_id();
+    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
+    write!(w, "{}", document_type_layout(cx, def_id));
+}
+
+fn render_enum_fields<'a>(
+    mut w: &mut Buffer,
+    cx: &mut Context<'_>,
+    g: Option<&clean::Generics>,
+    variants: impl Iterator<Item = &'a clean::Item>,
+    count_variants: usize,
+    has_stripped_entries: bool,
+    is_non_exhaustive: bool,
+) {
+    if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
+        // If there wasn't a `where` clause, we add a whitespace.
+        w.write_str(" ");
+    }
+
+    let variants_stripped = has_stripped_entries;
+    if count_variants == 0 && !variants_stripped {
+        w.write_str("{}");
+    } else {
+        w.write_str("{\n");
+        let toggle = should_hide_fields(count_variants);
+        if toggle {
+            toggle_open(&mut w, format_args!("{count_variants} variants"));
+        }
+        const TAB: &str = "    ";
+        for v in variants {
+            w.write_str(TAB);
+            let name = v.name.unwrap();
+            match *v.kind {
+                // FIXME(#101337): Show discriminant
+                clean::VariantItem(ref var) => match var.kind {
+                    clean::VariantKind::CLike => w.write_str(name.as_str()),
+                    clean::VariantKind::Tuple(ref s) => {
+                        write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
+                    }
+                    clean::VariantKind::Struct(ref s) => {
+                        render_struct(w, v, None, None, &s.fields, TAB, false, cx);
+                    }
+                },
+                _ => unreachable!(),
             }
-            w.write_str("}");
+            w.write_str(",\n");
         }
-    });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+        if variants_stripped && !is_non_exhaustive {
+            w.write_str("    // some variants omitted\n");
+        }
+        if toggle {
+            toggle_close(&mut w);
+        }
+        w.write_str("}");
+    }
+}
 
-    if count_variants != 0 {
+fn item_variants<'a>(
+    w: &mut Buffer,
+    cx: &mut Context<'_>,
+    it: &clean::Item,
+    variants: impl Iterator<Item = &'a clean::Item>,
+) {
+    let tcx = cx.tcx();
+    write!(
+        w,
+        "<h2 id=\"variants\" class=\"variants small-section-header\">\
+            Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\
+        </h2>\
+        {}\
+        <div class=\"variants\">",
+        document_non_exhaustive_header(it),
+        document_non_exhaustive(it)
+    );
+    for variant in variants {
+        let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
         write!(
             w,
-            "<h2 id=\"variants\" class=\"variants small-section-header\">\
-                Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\
-            </h2>\
-            {}\
-            <div class=\"variants\">",
-            document_non_exhaustive_header(it),
-            document_non_exhaustive(it)
+            "<section id=\"{id}\" class=\"variant\">\
+                <a href=\"#{id}\" class=\"anchor\">§</a>",
         );
-        for variant in e.variants() {
-            let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
-            write!(
-                w,
-                "<section id=\"{id}\" class=\"variant\">\
-                    <a href=\"#{id}\" class=\"anchor\">§</a>",
-            );
-            render_stability_since_raw_with_extra(
-                w,
-                variant.stable_since(tcx),
-                variant.const_stability(tcx),
-                it.stable_since(tcx),
-                it.const_stable_since(tcx),
-                " rightside",
-            );
-            write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
+        render_stability_since_raw_with_extra(
+            w,
+            variant.stable_since(tcx),
+            variant.const_stability(tcx),
+            it.stable_since(tcx),
+            it.const_stable_since(tcx),
+            " rightside",
+        );
+        write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
 
-            let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+        let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
 
-            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
-                write!(w, "({})", print_tuple_struct_fields(cx, s));
-            }
-            w.write_str("</h3></section>");
-
-            let heading_and_fields = match &variant_data.kind {
-                clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
-                clean::VariantKind::Tuple(fields) => {
-                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                    // the section if at least one field is documented.
-                    if fields.iter().any(|f| !f.doc_value().is_empty()) {
-                        Some(("Tuple Fields", fields))
-                    } else {
-                        None
-                    }
+        if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
+            write!(w, "({})", print_tuple_struct_fields(cx, s));
+        }
+        w.write_str("</h3></section>");
+
+        let heading_and_fields = match &variant_data.kind {
+            clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+            clean::VariantKind::Tuple(fields) => {
+                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                // the section if at least one field is documented.
+                if fields.iter().any(|f| !f.doc_value().is_empty()) {
+                    Some(("Tuple Fields", fields))
+                } else {
+                    None
                 }
-                clean::VariantKind::CLike => None,
-            };
+            }
+            clean::VariantKind::CLike => None,
+        };
 
-            if let Some((heading, fields)) = heading_and_fields {
-                let variant_id =
-                    cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
-                write!(
-                    w,
-                    "<div class=\"sub-variant\" id=\"{variant_id}\">\
-                        <h4>{heading}</h4>\
-                        {}",
-                    document_non_exhaustive(variant)
-                );
-                for field in fields {
-                    match *field.kind {
-                        clean::StrippedItem(box clean::StructFieldItem(_)) => {}
-                        clean::StructFieldItem(ref ty) => {
-                            let id = cx.derive_id(format!(
-                                "variant.{}.field.{}",
-                                variant.name.unwrap(),
-                                field.name.unwrap()
-                            ));
-                            write!(
-                                w,
-                                "<div class=\"sub-variant-field\">\
+        if let Some((heading, fields)) = heading_and_fields {
+            let variant_id =
+                cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
+            write!(
+                w,
+                "<div class=\"sub-variant\" id=\"{variant_id}\">\
+                    <h4>{heading}</h4>\
+                    {}",
+                document_non_exhaustive(variant)
+            );
+            for field in fields {
+                match *field.kind {
+                    clean::StrippedItem(box clean::StructFieldItem(_)) => {}
+                    clean::StructFieldItem(ref ty) => {
+                        let id = cx.derive_id(format!(
+                            "variant.{}.field.{}",
+                            variant.name.unwrap(),
+                            field.name.unwrap()
+                        ));
+                        write!(
+                            w,
+                            "<div class=\"sub-variant-field\">\
                                  <span id=\"{id}\" class=\"small-section-header\">\
                                      <a href=\"#{id}\" class=\"anchor field\">§</a>\
                                      <code>{f}: {t}</code>\
                                  </span>",
-                                f = field.name.unwrap(),
-                                t = ty.print(cx),
-                            );
-                            write!(
-                                w,
-                                "{}</div>",
-                                document(cx, field, Some(variant), HeadingOffset::H5)
-                            );
-                        }
-                        _ => unreachable!(),
+                            f = field.name.unwrap(),
+                            t = ty.print(cx),
+                        );
+                        write!(
+                            w,
+                            "{}</div>",
+                            document(cx, field, Some(variant), HeadingOffset::H5)
+                        );
                     }
+                    _ => unreachable!(),
                 }
-                w.write_str("</div>");
             }
-
-            write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4));
+            w.write_str("</div>");
         }
-        write!(w, "</div>");
+
+        write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4));
     }
-    let def_id = it.item_id.expect_def_id();
-    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
-    write!(w, "{}", document_type_layout(cx, def_id));
+    write!(w, "</div>");
 }
 
 fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
@@ -1593,15 +1699,28 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
 
     write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
 
-    let mut fields = s
-        .fields
+    item_fields(w, cx, it, &s.fields, s.ctor_kind);
+
+    let def_id = it.item_id.expect_def_id();
+    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
+    write!(w, "{}", document_type_layout(cx, def_id));
+}
+
+fn item_fields(
+    w: &mut Buffer,
+    cx: &mut Context<'_>,
+    it: &clean::Item,
+    fields: &Vec<clean::Item>,
+    ctor_kind: Option<CtorKind>,
+) {
+    let mut fields = fields
         .iter()
         .filter_map(|f| match *f.kind {
             clean::StructFieldItem(ref ty) => Some((f, ty)),
             _ => None,
         })
         .peekable();
-    if let None | Some(CtorKind::Fn) = s.ctor_kind {
+    if let None | Some(CtorKind::Fn) = ctor_kind {
         if fields.peek().is_some() {
             write!(
                 w,
@@ -1609,7 +1728,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
                      {}{}<a href=\"#fields\" class=\"anchor\">§</a>\
                  </h2>\
                  {}",
-                if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
+                if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
                 document_non_exhaustive_header(it),
                 document_non_exhaustive(it)
             );
@@ -1630,9 +1749,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
             }
         }
     }
-    let def_id = it.item_id.expect_def_id();
-    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
-    write!(w, "{}", document_type_layout(cx, def_id));
 }
 
 fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
@@ -1871,7 +1987,7 @@ fn render_union<'a, 'cx: 'a>(
 }
 
 fn render_struct(
-    mut w: &mut Buffer,
+    w: &mut Buffer,
     it: &clean::Item,
     g: Option<&clean::Generics>,
     ty: Option<CtorKind>,
@@ -1891,6 +2007,29 @@ fn render_struct(
     if let Some(g) = g {
         write!(w, "{}", g.print(cx))
     }
+    render_struct_fields(
+        w,
+        g,
+        ty,
+        fields,
+        tab,
+        structhead,
+        it.has_stripped_entries().unwrap_or(false),
+        cx,
+    )
+}
+
+fn render_struct_fields(
+    mut w: &mut Buffer,
+    g: Option<&clean::Generics>,
+    ty: Option<CtorKind>,
+    fields: &[clean::Item],
+    tab: &str,
+    structhead: bool,
+    has_stripped_entries: bool,
+    cx: &Context<'_>,
+) {
+    let tcx = cx.tcx();
     match ty {
         None => {
             let where_displayed =
@@ -1922,11 +2061,11 @@ fn render_struct(
             }
 
             if has_visible_fields {
-                if it.has_stripped_entries().unwrap() {
+                if has_stripped_entries {
                     write!(w, "\n{tab}    /* private fields */");
                 }
                 write!(w, "\n{tab}");
-            } else if it.has_stripped_entries().unwrap() {
+            } else if has_stripped_entries {
                 write!(w, " /* private fields */ ");
             }
             if toggle {
@@ -1936,21 +2075,31 @@ fn render_struct(
         }
         Some(CtorKind::Fn) => {
             w.write_str("(");
-            for (i, field) in fields.iter().enumerate() {
-                if i > 0 {
-                    w.write_str(", ");
-                }
-                match *field.kind {
-                    clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
-                    clean::StructFieldItem(ref ty) => {
-                        write!(
-                            w,
-                            "{}{}",
-                            visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
-                            ty.print(cx),
-                        )
+            if fields.iter().all(|field| {
+                matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
+            }) {
+                write!(w, "/* private fields */");
+            } else {
+                for (i, field) in fields.iter().enumerate() {
+                    if i > 0 {
+                        w.write_str(", ");
+                    }
+                    match *field.kind {
+                        clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
+                        clean::StructFieldItem(ref ty) => {
+                            write!(
+                                w,
+                                "{}{}",
+                                visibility_print_with_space(
+                                    field.visibility(tcx),
+                                    field.item_id,
+                                    cx
+                                ),
+                                ty.print(cx),
+                            )
+                        }
+                        _ => unreachable!(),
                     }
-                    _ => unreachable!(),
                 }
             }
             w.write_str(")");
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index b96b1536156..76f63c6f63e 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -82,7 +82,7 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf
         clean::PrimitiveItem(_) => sidebar_primitive(cx, it),
         clean::UnionItem(ref u) => sidebar_union(cx, it, u),
         clean::EnumItem(ref e) => sidebar_enum(cx, it, e),
-        clean::TypeAliasItem(_) => sidebar_type_alias(cx, it),
+        clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t),
         clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)],
         clean::ForeignTypeItem => sidebar_foreign_type(cx, it),
         _ => vec![],
@@ -230,8 +230,33 @@ fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBl
     }
 }
 
-fn sidebar_type_alias<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> {
+fn sidebar_type_alias<'a>(
+    cx: &'a Context<'_>,
+    it: &'a clean::Item,
+    t: &'a clean::TypeAlias,
+) -> Vec<LinkBlock<'a>> {
     let mut items = vec![];
+    if let Some(inner_type) = &t.inner_type {
+        items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type")));
+        match inner_type {
+            clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => {
+                let mut variants = variants
+                    .iter()
+                    .filter(|i| !i.is_stripped())
+                    .filter_map(|v| v.name)
+                    .map(|name| Link::new(format!("variant.{name}"), name.to_string()))
+                    .collect::<Vec<_>>();
+                variants.sort_unstable();
+
+                items.push(LinkBlock::new(Link::new("variants", "Variants"), variants));
+            }
+            clean::TypeAliasInnerType::Union { fields }
+            | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => {
+                let fields = get_struct_fields_name(fields);
+                items.push(LinkBlock::new(Link::new("fields", "Fields"), fields));
+            }
+        }
+    }
     sidebar_assoc_items(cx, it, &mut items);
     items
 }
@@ -254,11 +279,12 @@ fn sidebar_assoc_items<'a>(
     links: &mut Vec<LinkBlock<'a>>,
 ) {
     let did = it.item_id.expect_def_id();
-    let cache = cx.cache();
+    let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id());
+    let v = v.as_slice();
 
     let mut assoc_consts = Vec::new();
     let mut methods = Vec::new();
-    if let Some(v) = cache.impls.get(&did) {
+    if !v.is_empty() {
         let mut used_links = FxHashSet::default();
         let mut id_map = IdMap::new();
 
@@ -294,7 +320,7 @@ fn sidebar_assoc_items<'a>(
                     cx,
                     &mut deref_methods,
                     impl_,
-                    v,
+                    v.iter().copied(),
                     &mut derefs,
                     &mut used_links,
                 );
@@ -324,7 +350,7 @@ fn sidebar_deref_methods<'a>(
     cx: &'a Context<'_>,
     out: &mut Vec<LinkBlock<'a>>,
     impl_: &Impl,
-    v: &[Impl],
+    v: impl Iterator<Item = &'a Impl>,
     derefs: &mut DefIdSet,
     used_links: &mut FxHashSet<String>,
 ) {
@@ -349,7 +375,7 @@ fn sidebar_deref_methods<'a>(
             // Avoid infinite cycles
             return;
         }
-        let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
+        let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
         let inner_impl = target
             .def_id(c)
             .or_else(|| {
@@ -400,7 +426,7 @@ fn sidebar_deref_methods<'a>(
                 cx,
                 out,
                 target_deref_impl,
-                target_impls,
+                target_impls.iter(),
                 derefs,
                 used_links,
             );
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index cb653d6b8df..a5ae988f348 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -852,14 +852,14 @@ function preLoadCss(cssUrl) {
         window.CURRENT_TOOLTIP_ELEMENT = wrapper;
         window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
         clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
-        wrapper.onpointerenter = function(ev) {
+        wrapper.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
             clearTooltipHoverTimeout(e);
         };
-        wrapper.onpointerleave = function(ev) {
+        wrapper.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
@@ -963,38 +963,38 @@ function preLoadCss(cssUrl) {
     }
 
     onEachLazy(document.getElementsByClassName("tooltip"), e => {
-        e.onclick = function() {
-            this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
-            if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
+        e.onclick = () => {
+            e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;
+            if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {
                 hideTooltip(true);
             } else {
-                showTooltip(this);
+                showTooltip(e);
                 window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
                 window.CURRENT_TOOLTIP_ELEMENT.focus();
                 window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
             }
             return false;
         };
-        e.onpointerenter = function(ev) {
+        e.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            setTooltipHoverTimeout(this, true);
+            setTooltipHoverTimeout(e, true);
         };
-        e.onpointermove = function(ev) {
+        e.onpointermove = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            setTooltipHoverTimeout(this, true);
+            setTooltipHoverTimeout(e, true);
         };
-        e.onpointerleave = function(ev) {
+        e.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            if (!this.TOOLTIP_FORCE_VISIBLE &&
+            if (!e.TOOLTIP_FORCE_VISIBLE &&
                 !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
                 // Tooltip pointer leave gesture:
                 //
@@ -1139,7 +1139,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
      *
      * Pass "true" to reset focus for tooltip popovers.
      */
-    window.hideAllModals = function(switchFocus) {
+    window.hideAllModals = switchFocus => {
         hideSidebar();
         window.hidePopoverMenus();
         hideTooltip(switchFocus);
@@ -1148,7 +1148,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
     /**
      * Hide all the popover menus.
      */
-    window.hidePopoverMenus = function() {
+    window.hidePopoverMenus = () => {
         onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
             elem.style.display = "none";
         });
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2cba32c1b50..63947789c54 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -59,8 +59,8 @@
             if (settingValue !== null) {
                 toggle.checked = settingValue === "true";
             }
-            toggle.onchange = function() {
-                changeSetting(this.id, this.checked);
+            toggle.onchange = () => {
+                changeSetting(toggle.id, toggle.checked);
             };
         });
         onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
@@ -224,14 +224,14 @@
 
     if (isSettingsPage) {
         // We replace the existing "onclick" callback to do nothing if clicked.
-        getSettingsButton().onclick = function(event) {
+        getSettingsButton().onclick = event => {
             event.preventDefault();
         };
     } else {
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
         const settingsMenu = document.getElementById("settings");
-        settingsButton.onclick = function(event) {
+        settingsButton.onclick = event => {
             if (elemIsInParent(event.target, settingsMenu)) {
                 return;
             }
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 60ccfe4da44..8cb43634377 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -15,8 +15,7 @@
     <link rel="stylesheet" {#+ #}
           href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #}
     <link rel="stylesheet" {#+ #}
-          href="{{static_root_path|safe}}{{files.rustdoc_css}}" {#+ #}
-          id="mainThemeStyle"> {# #}
+          href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {# #}
     {% if !layout.default_settings.is_empty() %}
     <script id="default-settings" {#+ #}
       {%~ for (k, v) in layout.default_settings ~%}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 0c18f5687f5..08865015960 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -789,7 +789,7 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind
 
 impl FromWithTcx<Box<clean::TypeAlias>> for TypeAlias {
     fn from_tcx(type_alias: Box<clean::TypeAlias>, tcx: TyCtxt<'_>) -> Self {
-        let clean::TypeAlias { type_, generics, item_type: _ } = *type_alias;
+        let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias;
         TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) }
     }
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7b0a7a90d31..0db846bfc7e 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -16,7 +16,9 @@ use rustc_hir::Mutability;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
-use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
+use rustc_resolve::rustdoc::{
+    source_span_for_markdown_range, strip_generics_from_path, MalformedGenerics,
+};
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -1211,11 +1213,11 @@ impl LinkCollector<'_, '_> {
         ori_link: &MarkdownLinkRange,
         item: &Item,
     ) {
-        let span = super::source_span_for_markdown_range(
+        let span = source_span_for_markdown_range(
             self.cx.tcx,
             dox,
             ori_link.inner_range(),
-            &item.attrs,
+            &item.attrs.doc_strings,
         )
         .unwrap_or_else(|| item.attr_span(self.cx.tcx));
         rustc_session::parse::feature_err(
@@ -1702,26 +1704,27 @@ fn report_diagnostic(
         let (span, link_range) = match link_range {
             MarkdownLinkRange::Destination(md_range) => {
                 let mut md_range = md_range.clone();
-                let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs)
-                    .map(|mut sp| {
-                        while dox.as_bytes().get(md_range.start) == Some(&b' ')
-                            || dox.as_bytes().get(md_range.start) == Some(&b'`')
-                        {
-                            md_range.start += 1;
-                            sp = sp.with_lo(sp.lo() + BytePos(1));
-                        }
-                        while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
-                            || dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
-                        {
-                            md_range.end -= 1;
-                            sp = sp.with_hi(sp.hi() - BytePos(1));
-                        }
-                        sp
-                    });
+                let sp =
+                    source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings)
+                        .map(|mut sp| {
+                            while dox.as_bytes().get(md_range.start) == Some(&b' ')
+                                || dox.as_bytes().get(md_range.start) == Some(&b'`')
+                            {
+                                md_range.start += 1;
+                                sp = sp.with_lo(sp.lo() + BytePos(1));
+                            }
+                            while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
+                                || dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
+                            {
+                                md_range.end -= 1;
+                                sp = sp.with_hi(sp.hi() - BytePos(1));
+                            }
+                            sp
+                        });
                 (sp, MarkdownLinkRange::Destination(md_range))
             }
             MarkdownLinkRange::WholeLink(md_range) => (
-                super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs),
+                source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings),
                 link_range.clone(),
             ),
         };
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index 97078a5cb16..0c5cfffe1be 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -4,11 +4,11 @@
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 use core::ops::Range;
 use pulldown_cmark::{Event, Parser, Tag};
 use regex::Regex;
 use rustc_errors::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use std::mem;
 use std::sync::LazyLock;
 
@@ -21,8 +21,9 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     if !dox.is_empty() {
         let report_diag =
             |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| {
-                let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
-                    .unwrap_or_else(|| item.attr_span(cx.tcx));
+                let sp =
+                    source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
+                        .unwrap_or_else(|| item.attr_span(cx.tcx));
                 cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
                     lint.note("bare URLs are not automatically turned into clickable links")
                         .span_suggestion(
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 37e28e1fbca..316b1a41c7d 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -6,6 +6,7 @@ use rustc_errors::{
     Applicability, Diagnostic, Handler, LazyFallbackBundle,
 };
 use rustc_parse::parse_stream_from_source_str;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use rustc_session::parse::ParseSess;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::{FilePathMapping, SourceMap};
@@ -14,7 +15,6 @@ use rustc_span::{FileName, InnerSpan, DUMMY_SP};
 use crate::clean;
 use crate::core::DocContext;
 use crate::html::markdown::{self, RustCodeBlock};
-use crate::passes::source_span_for_markdown_range;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.opt_doc_value() {
@@ -77,11 +77,15 @@ fn check_rust_syntax(
     let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
 
     // The span and whether it is precise or not.
-    let (sp, precise_span) =
-        match source_span_for_markdown_range(cx.tcx, dox, &code_block.range, &item.attrs) {
-            Some(sp) => (sp, true),
-            None => (item.attr_span(cx.tcx), false),
-        };
+    let (sp, precise_span) = match source_span_for_markdown_range(
+        cx.tcx,
+        dox,
+        &code_block.range,
+        &item.attrs.doc_strings,
+    ) {
+        Some(sp) => (sp, true),
+        None => (item.attr_span(cx.tcx), false),
+    };
 
     let msg = if buffer.has_errors {
         "could not parse code block as Rust code"
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index c135c584cec..79fc599e176 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -2,9 +2,9 @@
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 
 use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 
 use std::iter::Peekable;
 use std::ops::Range;
@@ -20,7 +20,8 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let dox = item.doc_value();
     if !dox.is_empty() {
         let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| {
-            let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) {
+            let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs.doc_strings)
+            {
                 Some(sp) => sp,
                 None => item.attr_span(tcx),
             };
@@ -60,7 +61,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
                             tcx,
                             &dox,
                             &(generics_start..generics_end),
-                            &item.attrs,
+                            &item.attrs.doc_strings,
                         ) {
                             Some(sp) => sp,
                             None => item.attr_span(tcx),
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 67cd2cc9732..0c15bf5f764 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -6,6 +6,7 @@ use rustc_errors::SuggestionStyle;
 use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res};
 use rustc_hir::HirId;
 use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use rustc_span::Symbol;
 
 use crate::clean::utils::find_nearest_parent_module;
@@ -13,7 +14,6 @@ use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::Item;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 
 #[derive(Debug)]
 struct LinkData {
@@ -160,16 +160,21 @@ fn check_inline_or_reference_unknown_redundancy(
         (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
 
     if dest_res == display_res {
-        let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
-            .unwrap_or(item.attr_span(cx.tcx));
+        let link_span =
+            source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings)
+                .unwrap_or(item.attr_span(cx.tcx));
         let explicit_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_explicit_range(doc, link_range, open, close),
-            &item.attrs,
+            &item.attrs.doc_strings,
+        )?;
+        let display_span = source_span_for_markdown_range(
+            cx.tcx,
+            &doc,
+            &resolvable_link_range,
+            &item.attrs.doc_strings,
         )?;
-        let display_span =
-            source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
 
         cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
             lint.span_label(explicit_span, "explicit target is redundant")
@@ -201,21 +206,26 @@ fn check_reference_redundancy(
         (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
 
     if dest_res == display_res {
-        let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
-            .unwrap_or(item.attr_span(cx.tcx));
+        let link_span =
+            source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings)
+                .unwrap_or(item.attr_span(cx.tcx));
         let explicit_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_explicit_range(doc, link_range.clone(), b'[', b']'),
-            &item.attrs,
+            &item.attrs.doc_strings,
+        )?;
+        let display_span = source_span_for_markdown_range(
+            cx.tcx,
+            &doc,
+            &resolvable_link_range,
+            &item.attrs.doc_strings,
         )?;
-        let display_span =
-            source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
         let def_span = source_span_for_markdown_range(
             cx.tcx,
             &doc,
             &offset_reference_def_range(doc, dest, link_range),
-            &item.attrs,
+            &item.attrs.doc_strings,
         )?;
 
         cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs
index 256958d7160..8b7fdd6ab1f 100644
--- a/src/librustdoc/passes/lint/unescaped_backticks.rs
+++ b/src/librustdoc/passes/lint/unescaped_backticks.rs
@@ -3,10 +3,10 @@
 use crate::clean::Item;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
-use crate::passes::source_span_for_markdown_range;
 use pulldown_cmark::{BrokenLink, Event, Parser};
 use rustc_errors::DiagnosticBuilder;
 use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use std::ops::Range;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
@@ -52,7 +52,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
                     tcx,
                     &dox,
                     &(backtick_index..backtick_index + 1),
-                    &item.attrs,
+                    &item.attrs.doc_strings,
                 )
                 .unwrap_or_else(|| item.attr_span(tcx));
 
@@ -378,9 +378,12 @@ fn suggest_insertion(
     /// Maximum bytes of context to show around the insertion.
     const CONTEXT_MAX_LEN: usize = 80;
 
-    if let Some(span) =
-        source_span_for_markdown_range(cx.tcx, &dox, &(insert_index..insert_index), &item.attrs)
-    {
+    if let Some(span) = source_span_for_markdown_range(
+        cx.tcx,
+        &dox,
+        &(insert_index..insert_index),
+        &item.attrs.doc_strings,
+    ) {
         lint.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
     } else {
         let line_start = dox[..insert_index].rfind('\n').map_or(0, |idx| idx + 1);
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 4b1ff68df50..bb678e33888 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -1,11 +1,6 @@
 //! Contains information about "passes", used to modify crate information during the documentation
 //! process.
 
-use rustc_middle::ty::TyCtxt;
-use rustc_resolve::rustdoc::DocFragmentKind;
-use rustc_span::{InnerSpan, Span, DUMMY_SP};
-use std::ops::Range;
-
 use self::Condition::*;
 use crate::clean;
 use crate::core::DocContext;
@@ -115,89 +110,3 @@ impl ConditionalPass {
 pub(crate) fn defaults(show_coverage: bool) -> &'static [ConditionalPass] {
     if show_coverage { COVERAGE_PASSES } else { DEFAULT_PASSES }
 }
-
-/// Returns a span encompassing all the given attributes.
-pub(crate) fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
-    if attrs.doc_strings.is_empty() {
-        return None;
-    }
-    let start = attrs.doc_strings[0].span;
-    if start == DUMMY_SP {
-        return None;
-    }
-    let end = attrs.doc_strings.last().expect("no doc strings provided").span;
-    Some(start.to(end))
-}
-
-/// 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
-/// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
-/// that case due to escaping and other source features.
-pub(crate) fn source_span_for_markdown_range(
-    tcx: TyCtxt<'_>,
-    markdown: &str,
-    md_range: &Range<usize>,
-    attrs: &clean::Attributes,
-) -> Option<Span> {
-    let is_all_sugared_doc =
-        attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
-
-    if !is_all_sugared_doc {
-        return None;
-    }
-
-    let snippet = tcx.sess.source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?;
-
-    let starting_line = markdown[..md_range.start].matches('\n').count();
-    let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
-
-    // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
-    // CRLF and LF line endings the same way.
-    let mut src_lines = snippet.split_terminator('\n');
-    let md_lines = markdown.split_terminator('\n');
-
-    // The number of bytes from the source span to the markdown span that are not part
-    // of the markdown, like comment markers.
-    let mut start_bytes = 0;
-    let mut end_bytes = 0;
-
-    'outer: for (line_no, md_line) in md_lines.enumerate() {
-        loop {
-            let source_line = src_lines.next()?;
-            match source_line.find(md_line) {
-                Some(offset) => {
-                    if line_no == starting_line {
-                        start_bytes += offset;
-
-                        if starting_line == ending_line {
-                            break 'outer;
-                        }
-                    } else if line_no == ending_line {
-                        end_bytes += offset;
-                        break 'outer;
-                    } else if line_no < starting_line {
-                        start_bytes += source_line.len() - md_line.len();
-                    } else {
-                        end_bytes += source_line.len() - md_line.len();
-                    }
-                    break;
-                }
-                None => {
-                    // Since this is a source line that doesn't include a markdown line,
-                    // we have to count the newline that we split from earlier.
-                    if line_no <= starting_line {
-                        start_bytes += source_line.len() + 1;
-                    } else {
-                        end_bytes += source_line.len() + 1;
-                    }
-                }
-            }
-        }
-    }
-
-    Some(span_of_attrs(attrs)?.from_inner(InnerSpan::new(
-        md_range.start + start_bytes,
-        md_range.end + start_bytes + end_bytes,
-    )))
-}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 96fe1c9e1aecd8f57063e3753969bb6418fd2fd
+Subproject 2fc85d15a542bfb610aff7682073412cf635352
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index c0a9f466e7b..dcd9a4adcbd 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -15,7 +15,6 @@ clippy_utils = { path = "../clippy_utils" }
 declare_clippy_lint = { path = "../declare_clippy_lint" }
 if_chain = "1.0"
 itertools = "0.10.1"
-pulldown-cmark = { version = "0.9", default-features = false }
 quine-mc_cluskey = "0.2"
 regex-syntax = "0.7"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index e29ab634c97..d8f2fbcea00 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -1,18 +1,16 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 use if_chain::if_chain;
-use itertools::Itertools;
 use pulldown_cmark::Event::{
     Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
-use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
-use rustc_ast::token::CommentKind;
+use rustc_ast::ast::{Async, Attribute, Fn, FnRetTy, ItemKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
@@ -26,6 +24,9 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::ForceCollect;
+use rustc_resolve::rustdoc::{
+    add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment,
+};
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::edition::Edition;
@@ -450,53 +451,16 @@ fn lint_for_missing_headers(
     }
 }
 
-/// Cleanup documentation decoration.
-///
-/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
-/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
-/// need to keep track of
-/// the spans but this function is inspired from the later.
-#[expect(clippy::cast_possible_truncation)]
-#[must_use]
-pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
-    // one-line comments lose their prefix
-    if comment_kind == CommentKind::Line {
-        let mut doc = doc.to_owned();
-        doc.push('\n');
-        let len = doc.len();
-        // +3 skips the opening delimiter
-        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
-    }
+#[derive(Copy, Clone)]
+struct Fragments<'a> {
+    doc: &'a str,
+    fragments: &'a [DocFragment],
+}
 
-    let mut sizes = vec![];
-    let mut contains_initial_stars = false;
-    for line in doc.lines() {
-        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
-        debug_assert_eq!(offset as u32 as usize, offset);
-        contains_initial_stars |= line.trim_start().starts_with('*');
-        // +1 adds the newline, +3 skips the opening delimiter
-        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
-    }
-    if !contains_initial_stars {
-        return (doc.to_string(), sizes);
-    }
-    // remove the initial '*'s if any
-    let mut no_stars = String::with_capacity(doc.len());
-    for line in doc.lines() {
-        let mut chars = line.chars();
-        for c in &mut chars {
-            if c.is_whitespace() {
-                no_stars.push(c);
-            } else {
-                no_stars.push(if c == '*' { ' ' } else { c });
-                break;
-            }
-        }
-        no_stars.push_str(chars.as_str());
-        no_stars.push('\n');
+impl Fragments<'_> {
+    fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
+        source_span_for_markdown_range(cx.tcx, &self.doc, &range, &self.fragments)
     }
-
-    (no_stars, sizes)
 }
 
 #[derive(Copy, Clone, Default)]
@@ -515,27 +479,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         Some(("fake".into(), "fake".into()))
     }
 
+    let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
     let mut doc = String::new();
-    let mut spans = vec![];
-
-    for attr in attrs {
-        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
-            let (comment, current_spans) = strip_doc_comment_decoration(comment.as_str(), comment_kind, attr.span);
-            spans.extend_from_slice(&current_spans);
-            doc.push_str(&comment);
-        } else if attr.has_name(sym::doc) {
-            // ignore mix of sugared and non-sugared doc
-            // don't trigger the safety or errors check
-            return None;
-        }
-    }
-
-    let mut current = 0;
-    for &mut (ref mut offset, _) in &mut spans {
-        let offset_copy = *offset;
-        *offset = current;
-        current += offset_copy;
+    for fragment in &fragments {
+        add_doc_fragment(&mut doc, fragment);
     }
+    doc.pop();
 
     if doc.is_empty() {
         return Some(DocHeaders::default());
@@ -543,23 +492,19 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     let mut cb = fake_broken_link_callback;
 
-    let parser =
-        pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
-    // Iterate over all `Events` and combine consecutive events into one
-    let events = parser.coalesce(|previous, current| {
-        let previous_range = previous.1;
-        let current_range = current.1;
-
-        match (previous.0, current.0) {
-            (Text(previous), Text(current)) => {
-                let mut previous = previous.to_string();
-                previous.push_str(&current);
-                Ok((Text(previous.into()), previous_range))
-            },
-            (previous, current) => Err(((previous, previous_range), (current, current_range))),
-        }
-    });
-    Some(check_doc(cx, valid_idents, events, &spans))
+    // disable smart punctuation to pick up ['link'] more easily
+    let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION;
+    let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb));
+
+    Some(check_doc(
+        cx,
+        valid_idents,
+        parser.into_offset_iter(),
+        Fragments {
+            fragments: &fragments,
+            doc: &doc,
+        },
+    ))
 }
 
 const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
@@ -568,7 +513,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
     events: Events,
-    spans: &[(usize, Span)],
+    fragments: Fragments<'_>,
 ) -> DocHeaders {
     // true if a safety header was found
     let mut headers = DocHeaders::default();
@@ -579,8 +524,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut no_test = false;
     let mut edition = None;
     let mut ticks_unbalanced = false;
-    let mut text_to_check: Vec<(CowStr<'_>, Span)> = Vec::new();
-    let mut paragraph_span = spans.get(0).expect("function isn't called if doc comment is empty").1;
+    let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new();
+    let mut paragraph_range = 0..0;
     for (event, range) in events {
         match event {
             Start(CodeBlock(ref kind)) => {
@@ -613,25 +558,28 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     in_heading = true;
                 }
                 ticks_unbalanced = false;
-                let (_, span) = get_current_span(spans, range.start);
-                paragraph_span = first_line_of_span(cx, span);
+                paragraph_range = range;
             },
             End(Heading(_, _, _) | Paragraph | Item) => {
                 if let End(Heading(_, _, _)) = event {
                     in_heading = false;
                 }
-                if ticks_unbalanced {
+                if ticks_unbalanced
+                    && let Some(span) = fragments.span(cx, paragraph_range.clone())
+                {
                     span_lint_and_help(
                         cx,
                         DOC_MARKDOWN,
-                        paragraph_span,
+                        span,
                         "backticks are unbalanced",
                         None,
                         "a backtick may be missing a pair",
                     );
                 } else {
-                    for (text, span) in text_to_check {
-                        check_text(cx, valid_idents, &text, span);
+                    for (text, range) in text_to_check {
+                        if let Some(span) = fragments.span(cx, range) {
+                            check_text(cx, valid_idents, &text, span);
+                        }
                     }
                 }
                 text_to_check = Vec::new();
@@ -640,8 +588,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             Html(_html) => (),             // HTML is weird, just ignore it
             SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
             FootnoteReference(text) | Text(text) => {
-                let (begin, span) = get_current_span(spans, range.start);
-                paragraph_span = paragraph_span.with_hi(span.hi());
+                paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
                 if Some(&text) == in_link.as_ref() || ticks_unbalanced {
                     // Probably a link of the form `<http://example.com>`
@@ -658,19 +605,19 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 if in_code {
                     if is_rust && !no_test {
                         let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
-                        check_code(cx, &text, edition, span);
+                        check_code(cx, &text, edition, range.clone(), fragments);
                     }
                 } else {
-                    check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
-                    // Adjust for the beginning of the current `Event`
-                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
+                    if in_link.is_some() {
+                        check_link_quotes(cx, trimmed_text, range.clone(), fragments);
+                    }
                     if let Some(link) = in_link.as_ref()
                       && let Ok(url) = Url::parse(link)
                       && (url.scheme() == "https" || url.scheme() == "http") {
                         // Don't check the text associated with external URLs
                         continue;
                     }
-                    text_to_check.push((text, span));
+                    text_to_check.push((text, range));
                 }
             },
         }
@@ -678,36 +625,21 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     headers
 }
 
-fn check_link_quotes(
-    cx: &LateContext<'_>,
-    in_link: bool,
-    trimmed_text: &str,
-    span: Span,
-    range: &Range<usize>,
-    begin: usize,
-    text_len: usize,
-) {
-    if in_link && trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'') {
-        // fix the span to only point at the text within the link
-        let lo = span.lo() + BytePos::from_usize(range.start - begin);
+fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
+    if trimmed_text.starts_with('\'')
+        && trimmed_text.ends_with('\'')
+        && let Some(span) = fragments.span(cx, range)
+    {
         span_lint(
             cx,
             DOC_LINK_WITH_QUOTES,
-            span.with_lo(lo).with_hi(lo + BytePos::from_usize(text_len)),
+            span,
             "possible intra-doc link using quotes instead of backticks",
         );
     }
 }
 
-fn get_current_span(spans: &[(usize, Span)], idx: usize) -> (usize, Span) {
-    let index = match spans.binary_search_by(|c| c.0.cmp(&idx)) {
-        Ok(o) => o,
-        Err(e) => e - 1,
-    };
-    spans[index]
-}
-
-fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
+fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
     fn has_needless_main(code: String, edition: Edition) -> bool {
         rustc_driver::catch_fatal_errors(|| {
             rustc_span::create_session_globals_then(edition, || {
@@ -774,12 +706,13 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
         .unwrap_or_default()
     }
 
+    let trailing_whitespace = text.len() - text.trim_end().len();
+
     // Because of the global session, we need to create a new session in a different thread with
     // the edition we need.
     let text = text.to_owned();
-    if thread::spawn(move || has_needless_main(text, edition))
-        .join()
-        .expect("thread::spawn failed")
+    if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed")
+        && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
     {
         span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
     }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index ab71bfbdc58..20fdf26dc52 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -21,6 +21,7 @@
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
+extern crate pulldown_cmark;
 extern crate rustc_arena;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
@@ -37,6 +38,7 @@ extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
 extern crate rustc_parse;
+extern crate rustc_resolve;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index a1ea3a495eb..da8d8ed4c0f 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -507,20 +507,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
             && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
-            return unsafe_line.sf.lines(|lines| {
-                if comment_start_line.line >= unsafe_line.line {
-                    HasSafetyComment::No
-                } else {
-                    match text_has_safety_comment(
-                        src,
-                        &lines[comment_start_line.line + 1..=unsafe_line.line],
-                        unsafe_line.sf.start_pos,
-                    ) {
-                        Some(b) => HasSafetyComment::Yes(b),
-                        None => HasSafetyComment::No,
-                    }
+            return if comment_start_line.line >= unsafe_line.line {
+                HasSafetyComment::No
+            } else {
+                match text_has_safety_comment(
+                    src,
+                    &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos,
+                ) {
+                    Some(b) => HasSafetyComment::Yes(b),
+                    None => HasSafetyComment::No,
                 }
-            });
+            };
         }
     }
     HasSafetyComment::Maybe
@@ -551,20 +549,18 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H
             && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
-            return unsafe_line.sf.lines(|lines| {
-                if comment_start_line.line >= unsafe_line.line {
-                    HasSafetyComment::No
-                } else {
-                    match text_has_safety_comment(
-                        src,
-                        &lines[comment_start_line.line + 1..=unsafe_line.line],
-                        unsafe_line.sf.start_pos,
-                    ) {
-                        Some(b) => HasSafetyComment::Yes(b),
-                        None => HasSafetyComment::No,
-                    }
+            return if comment_start_line.line >= unsafe_line.line {
+                HasSafetyComment::No
+            } else {
+                match text_has_safety_comment(
+                    src,
+                    &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos,
+                ) {
+                    Some(b) => HasSafetyComment::Yes(b),
+                    None => HasSafetyComment::No,
                 }
-            });
+            };
         }
     }
     HasSafetyComment::Maybe
@@ -614,20 +610,18 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
             && Lrc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
-            unsafe_line.sf.lines(|lines| {
-                if macro_line.line < unsafe_line.line {
-                    match text_has_safety_comment(
-                        src,
-                        &lines[macro_line.line + 1..=unsafe_line.line],
-                        unsafe_line.sf.start_pos,
-                    ) {
-                        Some(b) => HasSafetyComment::Yes(b),
-                        None => HasSafetyComment::No,
-                    }
-                } else {
-                    HasSafetyComment::No
+            if macro_line.line < unsafe_line.line {
+                match text_has_safety_comment(
+                    src,
+                    &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos,
+                ) {
+                    Some(b) => HasSafetyComment::Yes(b),
+                    None => HasSafetyComment::No,
                 }
-            })
+            } else {
+                HasSafetyComment::No
+            }
         } else {
             // Problem getting source text. Pretend a comment was found.
             HasSafetyComment::Maybe
@@ -671,13 +665,11 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
             // Get the text from the start of function body to the unsafe block.
             //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
             //              ^-------------^
-            unsafe_line.sf.lines(|lines| {
-                body_line.line < unsafe_line.line && text_has_safety_comment(
-                    src,
-                    &lines[body_line.line + 1..=unsafe_line.line],
-                    unsafe_line.sf.start_pos,
-                ).is_some()
-            })
+            body_line.line < unsafe_line.line && text_has_safety_comment(
+                src,
+                &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
+                unsafe_line.sf.start_pos,
+            ).is_some()
         } else {
             // Problem getting source text. Pretend a comment was found.
             true
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 03416d35ba4..600cd084c19 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -118,7 +118,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
 fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
     let span = original_sp(span, DUMMY_SP);
     let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
-    let line_start = sf.lines(|lines| lines[line]);
+    let line_start = sf.lines()[line];
     let line_start = sf.absolute_position(line_start);
     span.with_lo(line_start)
 }
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index e329a94ff6a..c1c3d4a868f 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -130,7 +130,9 @@ fn base_config(test_dir: &str) -> (Config, Args) {
     };
 
     let mut config = Config {
-        mode: Mode::Yolo { rustfix: RustfixMode::Everything },
+        mode: Mode::Yolo {
+            rustfix: RustfixMode::Everything,
+        },
         stderr_filters: vec![(Match::PathBackslash, b"/")],
         stdout_filters: vec![],
         output_conflict_handling: if bless {
diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed
index 945ba83611c..b506a9890f5 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.fixed
+++ b/src/tools/clippy/tests/ui/allow_attributes.fixed
@@ -22,6 +22,13 @@ struct T4;
 #[cfg_attr(panic = "unwind", expect(dead_code))]
 struct CfgT;
 
+#[allow(clippy::allow_attributes, unused)]
+struct Allowed;
+
+#[expect(clippy::allow_attributes)]
+#[allow(unused)]
+struct Expected;
+
 fn ignore_external() {
     external! {
         #[allow(clippy::needless_borrow)] // Should not lint
diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs
index 8afa61c7002..c7daa7abd9d 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.rs
+++ b/src/tools/clippy/tests/ui/allow_attributes.rs
@@ -22,6 +22,13 @@ struct T4;
 #[cfg_attr(panic = "unwind", allow(dead_code))]
 struct CfgT;
 
+#[allow(clippy::allow_attributes, unused)]
+struct Allowed;
+
+#[expect(clippy::allow_attributes)]
+#[allow(unused)]
+struct Expected;
+
 fn ignore_external() {
     external! {
         #[allow(clippy::needless_borrow)] // Should not lint
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
index d04ea7151c2..afb634f34b4 100644
--- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
@@ -1,17 +1,12 @@
 error: `clippy::restriction` is not meant to be enabled as a group
-   |
-   = note: because of the command line `--warn clippy::restriction`
-   = help: enable the restriction lints you need individually
-   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]`
-
-error: `clippy::restriction` is not meant to be enabled as a group
   --> $DIR/blanket_clippy_restriction_lints.rs:6:9
    |
 LL | #![warn(clippy::restriction)]
    |         ^^^^^^^^^^^^^^^^^^^
    |
    = help: enable the restriction lints you need individually
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]`
 
 error: `clippy::restriction` is not meant to be enabled as a group
   --> $DIR/blanket_clippy_restriction_lints.rs:8:9
@@ -29,5 +24,10 @@ LL | #![forbid(clippy::restriction)]
    |
    = help: enable the restriction lints you need individually
 
+error: `clippy::restriction` is not meant to be enabled as a group
+   |
+   = note: because of the command line `--warn clippy::restriction`
+   = help: enable the restriction lints you need individually
+
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index f7c2f14a482..47b56960a00 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -198,6 +198,16 @@ fn pulldown_cmark_crash() {}
 /// [plain text][path::to::item]
 fn intra_doc_link() {}
 
+/// Ignore escaped\_underscores
+///
+/// \\[
+///     \\prod\_{x\\in X} p\_x
+/// \\]
+fn issue_2581() {}
+
+/// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
+fn lint_after_escaped_chars() {}
+
 // issue #7033 - generic_const_exprs ICE
 struct S<T, const N: usize>
 where [(); N.checked_next_power_of_two().unwrap()]: {
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 51961e75b84..4d9a4eafa5f 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -198,6 +198,16 @@ fn pulldown_cmark_crash() {}
 /// [plain text][path::to::item]
 fn intra_doc_link() {}
 
+/// Ignore escaped\_underscores
+///
+/// \\[
+///     \\prod\_{x\\in X} p\_x
+/// \\]
+fn issue_2581() {}
+
+/// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
+fn lint_after_escaped_chars() {}
+
 // issue #7033 - generic_const_exprs ICE
 struct S<T, const N: usize>
 where [(); N.checked_next_power_of_two().unwrap()]: {
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index a30ded81385..4c9ff41d918 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -308,5 +308,16 @@ help: try
 LL | /// An iterator over `mycrate::Collection`'s values.
    |                      ~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 28 previous errors
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:208:34
+   |
+LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
+   |                                  ^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
+   |                                  ~~~~~~~~~~~~~~~~~
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 4a1711f79a0..6f7bab72040 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -48,4 +48,4 @@ fn other_markdown() {}
 ///   /// `lol`
 ///   pub struct Struct;
 ///   ```
-fn iss_7421() {}
+fn issue_7421() {}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 92b6f8536c8..89ad8db3916 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -1,7 +1,8 @@
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:7:1
+  --> $DIR/unbalanced_ticks.rs:7:5
    |
-LL | / /// This is a doc comment with `unbalanced_tick marks and several words that
+LL |   /// This is a doc comment with `unbalanced_tick marks and several words that
+   |  _____^
 LL | |
 LL | | /// should be `encompassed_by` tick marks because they `contain_underscores`.
 LL | | /// Because of the initial `unbalanced_tick` pair, the error message is
@@ -13,10 +14,10 @@ LL | | /// very `confusing_and_misleading`.
    = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]`
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:14:1
+  --> $DIR/unbalanced_ticks.rs:14:5
    |
 LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
@@ -32,10 +33,10 @@ LL | /// This paragraph is fine and `should_be` linted normally.
    |                                ~~~~~~~~~~~
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:20:1
+  --> $DIR/unbalanced_ticks.rs:20:5
    |
 LL | /// Double unbalanced backtick from ``here to here` should lint.
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
@@ -51,18 +52,18 @@ LL | /// ## `not_fine`
    |        ~~~~~~~~~~
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:37:1
+  --> $DIR/unbalanced_ticks.rs:37:5
    |
 LL | /// ### `unbalanced
-   | ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
 error: backticks are unbalanced
-  --> $DIR/unbalanced_ticks.rs:40:1
+  --> $DIR/unbalanced_ticks.rs:40:5
    |
 LL | /// - This `item has unbalanced tick marks
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: a backtick may be missing a pair
 
diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs
index 86721f61d19..d661231c59e 100644
--- a/src/tools/clippy/tests/ui/doc_errors.rs
+++ b/src/tools/clippy/tests/ui/doc_errors.rs
@@ -85,6 +85,22 @@ impl Struct1 {
     async fn async_priv_method_missing_errors_header() -> Result<(), ()> {
         unimplemented!();
     }
+
+    /**
+    # Errors
+    A description of the errors goes here.
+    */
+    fn block_comment() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /**
+     * # Errors
+     * A description of the errors goes here.
+     */
+    fn block_comment_leading_asterisks() -> Result<(), ()> {
+        unimplemented!();
+    }
 }
 
 pub trait Trait1 {
diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr
index 9cea864f1d8..28b2db2440b 100644
--- a/src/tools/clippy/tests/ui/doc_errors.stderr
+++ b/src/tools/clippy/tests/ui/doc_errors.stderr
@@ -38,7 +38,7 @@ LL |     pub async fn async_pub_method_missing_errors_header() -> Result<(), ()>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:92:5
+  --> $DIR/doc_errors.rs:108:5
    |
 LL |     fn trait_method_missing_errors_header() -> Result<(), ()>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.rs b/src/tools/clippy/tests/ui/needless_doc_main.rs
index d31b9047eaa..fee05926ce4 100644
--- a/src/tools/clippy/tests/ui/needless_doc_main.rs
+++ b/src/tools/clippy/tests/ui/needless_doc_main.rs
@@ -10,7 +10,7 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// With an explicit return type it should lint too
 /// ```edition2015
 /// fn main() -> () {
@@ -18,7 +18,7 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// This should, too.
 /// ```rust
 /// fn main() {
@@ -26,11 +26,12 @@
 ///     unimplemented!();
 /// }
 /// ```
-/// 
+///
 /// This one too.
 /// ```no_run
-/// fn main() {
+/// // the fn is not always the first line
 //~^ ERROR: needless `fn main` in doctest
+/// fn main() {
 ///     unimplemented!();
 /// }
 /// ```
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.stderr b/src/tools/clippy/tests/ui/needless_doc_main.stderr
index 8dd93bb05dd..84256548671 100644
--- a/src/tools/clippy/tests/ui/needless_doc_main.stderr
+++ b/src/tools/clippy/tests/ui/needless_doc_main.stderr
@@ -1,29 +1,47 @@
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:7:4
+  --> $DIR/needless_doc_main.rs:7:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
    |
    = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]`
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:16:4
+  --> $DIR/needless_doc_main.rs:16:5
    |
-LL | /// fn main() -> () {
-   |    ^^^^^^^^^^^^^^^^^^
+LL |   /// fn main() -> () {
+   |  _____^
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:24:4
+  --> $DIR/needless_doc_main.rs:24:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:32:4
+  --> $DIR/needless_doc_main.rs:32:5
    |
-LL | /// fn main() {
-   |    ^^^^^^^^^^^^
+LL |   /// // the fn is not always the first line
+   |  _____^
+LL | |
+LL | | /// fn main() {
+LL | | ///     unimplemented!();
+LL | | /// }
+   | |_____^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 97718f1f4a9..1e9219d4bb2 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
 
     fn after_analysis<'tcx>(
         &mut self,
-        handler: &EarlyErrorHandler,
         _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
@@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
 
-            init_late_loggers(handler, tcx);
+            let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
+            init_late_loggers(&handler, tcx);
             if !tcx.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 4f249acda1d..cb095f94f35 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>(
     e: InterpErrorInfo<'tcx>,
 ) -> Option<(i64, bool)> {
     use InterpError::*;
+    use UndefinedBehaviorInfo::*;
 
     let mut msg = vec![];
 
@@ -271,7 +272,7 @@ pub fn report_error<'tcx, 'mir>(
         (title, helps)
     } else {
         let title = match e.kind() {
-            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
+            UndefinedBehavior(ValidationError(validation_err))
                 if matches!(
                     validation_err.kind,
                     ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer
@@ -299,7 +300,7 @@ pub fn report_error<'tcx, 'mir>(
         let helps = match e.kind() {
             Unsupported(_) =>
                 vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
-            UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
+            UndefinedBehavior(AlignmentCheckFailed { .. })
                 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
             =>
                 vec![
@@ -311,13 +312,20 @@ pub fn report_error<'tcx, 'mir>(
                     (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                     (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                 ];
-                if let UndefinedBehaviorInfo::PointerUseAfterFree(alloc_id, _) | UndefinedBehaviorInfo::PointerOutOfBounds { alloc_id, .. } = info {
-                    if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
-                        helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
+                match info {
+                    PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
+                        if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
+                            helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
+                        }
+                        if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
+                            helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
+                        }
                     }
-                    if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
-                        helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
+                    AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
+                        helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")));
+                        helps.push((None, format!("if you think this code should be accepted anyway, please report an issue")));
                     }
+                    _ => {},
                 }
                 helps
             }
@@ -339,7 +347,7 @@ pub fn report_error<'tcx, 'mir>(
     // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
     let mut extra = String::new();
     match e.kind() {
-        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
+        UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
             writeln!(
                 extra,
                 "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
index 50d4228c111..d1ccaf89974 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr
@@ -6,6 +6,8 @@ LL |     g(Default::default())
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
index a53126c733e..3875c2617bb 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
@@ -6,6 +6,8 @@ LL |     g(42)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
index 6eacfeece14..6d1bdfee007 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
@@ -6,6 +6,8 @@ LL |     g(&42 as *const i32)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
index eedc1235773..07d76c90e5e 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr
@@ -6,6 +6,8 @@ LL |     g()
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
index bc500a90b77..7ac2bc2739f 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr
@@ -6,6 +6,8 @@ LL |     g(42)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
index 7dcca1e85b8..e082eb9e3e3 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr
@@ -6,6 +6,8 @@ LL |     g(Default::default())
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue
    = note: BACKTRACE:
    = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs
index 6ab73569c63..6ab73569c63 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr
index 133e4b2c16a..21e403b47f8 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr
@@ -1,5 +1,5 @@
 error: Undefined Behavior: constructing invalid value: encountered a null reference
-  --> $DIR/cast_fn_ptr1.rs:LL:CC
+  --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC
    |
 LL |     g(0usize as *const i32)
    |     ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
@@ -7,7 +7,7 @@ LL |     g(0usize as *const i32)
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC
+   = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
new file mode 100644
index 00000000000..7cdc15c6094
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
@@ -0,0 +1,28 @@
+#![allow(internal_features)]
+#![feature(core_intrinsics, custom_mir)]
+
+use std::intrinsics::mir::*;
+use std::num::NonZeroU32;
+use std::ptr;
+
+// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that
+// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer
+// type. That way we never get an "invalid value constructed" error inside the function, it can
+// only possibly be detected when the return value is passed to the caller.
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn f() -> NonZeroU32 {
+    mir! {
+        {
+            let tmp = ptr::addr_of_mut!(RET);
+            let ptr = tmp as *mut u32;
+            *ptr = 0;
+            Return()
+        }
+    }
+}
+
+fn main() {
+    let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) };
+    // There's a NonZeroU32-to-u32 transmute happening here
+    f(); //~ERROR: expected something greater or equal to 1
+}
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
new file mode 100644
index 00000000000..ccfb8890939
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
+  --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
+   |
+LL |     f();
+   |     ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
new file mode 100644
index 00000000000..ee80186d4b5
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
@@ -0,0 +1,34 @@
+#![allow(internal_features)]
+#![feature(core_intrinsics, custom_mir)]
+
+use std::intrinsics::mir::*;
+use std::num::NonZeroU32;
+use std::ptr;
+
+fn f(c: u32) {
+    println!("{c}");
+}
+
+// Call that function in a bad way, with an invalid NonZeroU32, but without
+// ever materializing this as a NonZeroU32 value outside the call itself.
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn call(f: fn(NonZeroU32)) {
+    mir! {
+        let _res: ();
+        {
+            let c = 0;
+            let tmp = ptr::addr_of!(c);
+            let ptr = tmp as *const NonZeroU32;
+            // The call site now is a NonZeroU32-to-u32 transmute.
+            Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1
+        }
+        retblock = {
+            Return()
+        }
+    }
+}
+
+fn main() {
+    let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) };
+    call(f);
+}
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
new file mode 100644
index 00000000000..234c2804008
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
+  --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
+   |
+LL |             Call(_res = f(*ptr), retblock)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
+note: inside `main`
+  --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
+   |
+LL |     call(f);
+   |     ^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs
index 64ddb563be5..64ddb563be5 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr
index 21001f2b460..bd9866acbd4 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr
@@ -1,5 +1,5 @@
 error: Undefined Behavior: constructing invalid value: encountered a null reference
-  --> $DIR/cast_fn_ptr2.rs:LL:CC
+  --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC
    |
 LL |     let _x = g();
    |              ^^^ constructing invalid value: encountered a null reference
@@ -7,7 +7,7 @@ LL |     let _x = g();
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC
+   = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
index 08be29115ca..2e1ab58db7a 100644
--- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs
+++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
@@ -1,10 +1,17 @@
 use std::mem;
 use std::num;
+use std::ptr;
 
 #[derive(Copy, Clone, Default)]
 struct Zst;
 
-fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+struct Wrapper<T>(T);
+
+fn id<T>(x: T) -> T { x }
+
+fn test_abi_compat<T: Clone, U: Clone>(t: T, u: U) {
     fn id<T>(x: T) -> T {
         x
     }
@@ -16,10 +23,10 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
     // in both directions.
     let f: fn(T) -> T = id;
     let f: fn(U) -> U = unsafe { std::mem::transmute(f) };
-    let _val = f(u);
+    let _val = f(u.clone());
     let f: fn(U) -> U = id;
     let f: fn(T) -> T = unsafe { std::mem::transmute(f) };
-    let _val = f(t);
+    let _val = f(t.clone());
 
     // And then we do the same for `extern "C"`.
     let f: extern "C" fn(T) -> T = id_c;
@@ -34,9 +41,6 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
 fn test_abi_newtype<T: Copy + Default>() {
     #[repr(transparent)]
     #[derive(Copy, Clone)]
-    struct Wrapper1<T>(T);
-    #[repr(transparent)]
-    #[derive(Copy, Clone)]
     struct Wrapper2<T>(T, ());
     #[repr(transparent)]
     #[derive(Copy, Clone)]
@@ -46,7 +50,7 @@ fn test_abi_newtype<T: Copy + Default>() {
     struct Wrapper3<T>(Zst, T, [u8; 0]);
 
     let t = T::default();
-    test_abi_compat(t, Wrapper1(t));
+    test_abi_compat(t, Wrapper(t));
     test_abi_compat(t, Wrapper2(t, ()));
     test_abi_compat(t, Wrapper2a((), t));
     test_abi_compat(t, Wrapper3(Zst, t, []));
@@ -54,23 +58,30 @@ fn test_abi_newtype<T: Copy + Default>() {
 }
 
 fn main() {
-    // Here we check:
-    // - u32 vs char is allowed
-    // - u32 vs NonZeroU32/Option<NonZeroU32> is allowed
-    // - reference vs raw pointer is allowed
-    // - references to things of the same size and alignment are allowed
-    // These are very basic tests that should work on all ABIs. However it is not clear that any of
-    // these would be stably guaranteed. Code that relies on this is equivalent to code that relies
-    // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields
-    // of a struct (even with `repr(C)`) will not always be accepted by Miri.
-    // Note that `bool` and `u8` are *not* compatible, at least on x86-64!
-    // One of them has `arg_ext: Zext`, the other does not.
-    // Similarly, `i32` and `u32` are not compatible on s390x due to different `arg_ext`.
-    test_abi_compat(0u32, 'x');
+    // Here we check some of the guaranteed ABI compatibilities.
+    // Different integer types of the same size and sign.
+    if cfg!(target_pointer_width = "32") {
+        test_abi_compat(0usize, 0u32);
+        test_abi_compat(0isize, 0i32);
+    } else {
+        test_abi_compat(0usize, 0u64);
+        test_abi_compat(0isize, 0i64);
+    }
     test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
-    test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
+    // Reference/pointer types with the same pointee.
     test_abi_compat(&0u32, &0u32 as *const u32);
+    test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32));
+    test_abi_compat(&(), ptr::NonNull::<()>::dangling());
+    // Reference/pointer types with different but sized pointees.
     test_abi_compat(&0u32, &([true; 4], [0u32; 0]));
+    // `fn` types
+    test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
+    // Guaranteed null-pointer-optimizations.
+    test_abi_compat(&0u32 as *const u32, Some(&0u32));
+    test_abi_compat(main as fn(), Some(main as fn()));
+    test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
+    test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32)));
+    test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap())));
 
     // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible
     // with the wrapped field.
diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs
new file mode 100644
index 00000000000..b1475ee7931
--- /dev/null
+++ b/tests/codegen/debuginfo-inline-callsite-location.rs
@@ -0,0 +1,28 @@
+// compile-flags: -g -O
+
+// Check that each inline call site for the same function uses the same "sub-program" so that LLVM
+// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail
+// calls to panic.
+
+// CHECK:       tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E
+// CHECK-SAME:  !dbg ![[#first_dbg:]]
+// CHECK:       tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E
+// CHECK-SAME:  !dbg ![[#second_dbg:]]
+
+// CHECK-DAG:   ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap<i32>"
+// CHECK-DAG:   ![[#first_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
+// CHECK:       ![[#second_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
+// CHECK:       ![[#first_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#first_scope]], inlinedAt: ![[#]])
+// CHECK:       ![[#second_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#second_scope]], inlinedAt: ![[#]])
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+extern "C" fn add_numbers(x: &Option<i32>, y: &Option<i32>) -> i32 {
+    let x1 = x.unwrap();
+    let y1 = y.unwrap();
+
+    x1 + y1
+}
diff --git a/tests/codegen/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
new file mode 100644
index 00000000000..142e3596d96
--- /dev/null
+++ b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
@@ -0,0 +1,46 @@
+// compile-flags: -O -Ccodegen-units=1
+
+#![crate_type = "lib"]
+
+#[repr(i64)]
+pub enum Boolean {
+    False = 0,
+    True = 1,
+}
+
+impl Clone for Boolean {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Copy for Boolean {}
+
+extern "C" {
+    fn set_value(foo: *mut i64);
+    fn bar();
+}
+
+pub fn foo(x: bool) {
+    let mut foo = core::mem::MaybeUninit::<i64>::uninit();
+    unsafe {
+        set_value(foo.as_mut_ptr());
+    }
+
+    if x {
+        let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
+        if matches!(l1, Boolean::False) {
+            unsafe {
+                *foo.as_mut_ptr() = 0;
+            }
+        }
+    }
+
+    let l2 = unsafe { *foo.as_mut_ptr() };
+    if l2 == 2 {
+        // CHECK: call void @bar
+        unsafe {
+            bar();
+        }
+    }
+}
diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs
index b140fc719da..c5974248bb3 100644
--- a/tests/codegen/repr/transparent.rs
+++ b/tests/codegen/repr/transparent.rs
@@ -43,7 +43,6 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 #[repr(transparent)]
 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
 
-// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
 // CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
diff --git a/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs
new file mode 100644
index 00000000000..a70ef7751b6
--- /dev/null
+++ b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs
@@ -0,0 +1,43 @@
+// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`.
+// This is a regression test for https://github.com/rust-lang/rust/issues/113404
+//
+// Notes about the `compile-flags` below:
+//
+// * The original issue only reproed with LTO - this is why this angle has
+//   extra test coverage via different `revisions`
+// * To observe the failure/repro at LLVM-IR level we need to use `staticlib`
+//   which necessitates `-C prefer-dynamic=false` - without the latter flag,
+//   we would have run into "cannot prefer dynamic linking when performing LTO".
+//
+// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target
+// specific.  In particular, `___asan_globals_registered` is only used in the
+// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths.  The `only-linux` filter is
+// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a
+// linux-only regression test should be sufficient here.
+//
+// needs-sanitizer-address
+// only-linux
+//
+// revisions:ASAN ASAN-FAT-LTO
+//[ASAN]          compile-flags: -Zsanitizer=address
+//[ASAN-FAT-LTO]  compile-flags: -Zsanitizer=address -Cprefer-dynamic=false -Clto=fat
+
+#![crate_type="staticlib"]
+
+// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which
+// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly
+// reported as an ODR violation in https://crbug.com/1459233#c1.  Before this bug was fixed,
+// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden
+// global i64`.  (The test expectations ignore the exact type because on `arm-android` the type
+// is `i32` rather than `i64`.)
+//
+// CHECK: @___asan_globals_registered = common hidden global
+// CHECK: @__start_asan_globals = extern_weak hidden global
+// CHECK: @__stop_asan_globals = extern_weak hidden global
+#[no_mangle]
+pub static CACHED_POW10: [(u64, i16, i16); 4] = [
+    (0xe61acf033d1a45df, -1087, -308),
+    (0xab70fe17c79ac6ca, -1060, -300),
+    (0xff77b1fcbebcdc4f, -1034, -292),
+    (0xbe5691ef416bd60c, -1007, -284),
+];
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index 80ac92d59f3..b06666c9dd7 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -2,7 +2,14 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: impl std::future::Future<Output = ()>,
+            ty: Alias(
+                Opaque,
+                AliasTy {
+                    args: [
+                    ],
+                    def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}),
+                },
+            ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:15:9: 15:14 (#8),
                 scope: scope[0],
@@ -10,7 +17,14 @@
             ignore_for_traits: false,
         },
         _1: GeneratorSavedTy {
-            ty: impl std::future::Future<Output = ()>,
+            ty: Alias(
+                Opaque,
+                AliasTy {
+                    args: [
+                    ],
+                    def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}),
+                },
+            ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:16:9: 16:14 (#10),
                 scope: scope[0],
diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
index 255ec94816c..ed47baa67da 100644
--- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
+++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
@@ -33,14 +33,22 @@
                           let _15: bool;
                           let _16: u32;
                           scope 6 {
-                              debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, };
+-                             debug ((f: (bool, bool, u32)).0: bool) => _14;
+-                             debug ((f: (bool, bool, u32)).1: bool) => _15;
+-                             debug ((f: (bool, bool, u32)).2: u32) => _16;
++                             debug ((f: (bool, bool, u32)).0: bool) => const true;
++                             debug ((f: (bool, bool, u32)).1: bool) => const false;
++                             debug ((f: (bool, bool, u32)).2: u32) => const 123_u32;
                               let _10: std::option::Option<u16>;
                               scope 7 {
                                   debug o => _10;
                                   let _17: u32;
                                   let _18: u32;
                                   scope 8 {
-                                      debug p => Point{ .0 => _17, .1 => _18, };
+-                                     debug ((p: Point).0: u32) => _17;
+-                                     debug ((p: Point).1: u32) => _18;
++                                     debug ((p: Point).0: u32) => const 32_u32;
++                                     debug ((p: Point).1: u32) => const 32_u32;
                                       let _11: u32;
                                       scope 9 {
 -                                         debug a => _11;
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff
index 55c774d555d..e443c8991f9 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff
@@ -34,11 +34,11 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
-          _7 = const 3_usize;
+          _7 = Len((*_1));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 3_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
index dcab570ea77..592f43f4739 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
@@ -34,11 +34,11 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
-          _7 = const 3_usize;
+          _7 = Len((*_1));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 3_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff
index 55c774d555d..e443c8991f9 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff
@@ -34,11 +34,11 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
-          _7 = const 3_usize;
+          _7 = Len((*_1));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 3_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
index dcab570ea77..592f43f4739 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
@@ -34,11 +34,11 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
-          _7 = const 3_usize;
+          _7 = Len((*_1));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 3_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
index 7931c4f02ae..d6b1a93f304 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -1,8 +1,7 @@
 // unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
-
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs
index 6c03fe9d9c2..d226bd54671 100644
--- a/tests/mir-opt/const_prop/large_array_index.rs
+++ b/tests/mir-opt/const_prop/large_array_index.rs
@@ -1,6 +1,5 @@
 // unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR large_array_index.main.ConstProp.diff
diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs
index 21dba84af37..fb8b825ee36 100644
--- a/tests/mir-opt/const_prop/repeat.rs
+++ b/tests/mir-opt/const_prop/repeat.rs
@@ -1,6 +1,5 @@
 // unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR repeat.main.ConstProp.diff
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff
new file mode 100644
index 00000000000..212ddc5b154
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: [u32; 4];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff
new file mode 100644
index 00000000000..5c53d4f4461
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: [u32; 4];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff
new file mode 100644
index 00000000000..212ddc5b154
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: [u32; 4];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff
new file mode 100644
index 00000000000..5c53d4f4461
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: [u32; 4];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs
new file mode 100644
index 00000000000..ddb3646ca9b
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/array_index.rs
@@ -0,0 +1,8 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR array_index.main.DataflowConstProp.diff
+fn main() {
+    let x: u32 = [0, 1, 2, 3][2];
+}
diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs
new file mode 100644
index 00000000000..9e911e85b88
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs
@@ -0,0 +1,10 @@
+// unit-test: DataflowConstProp
+
+// EMIT_MIR boolean_identities.test.DataflowConstProp.diff
+pub fn test(x: bool, y: bool) -> bool {
+    (y | true) & (x & false)
+}
+
+fn main() {
+    test(true, false);
+}
diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff
new file mode 100644
index 00000000000..5440c38ce4b
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff
@@ -0,0 +1,33 @@
+- // MIR for `test` before DataflowConstProp
++ // MIR for `test` after DataflowConstProp
+  
+  fn test(_1: bool, _2: bool) -> bool {
+      debug x => _1;
+      debug y => _2;
+      let mut _0: bool;
+      let mut _3: bool;
+      let mut _4: bool;
+      let mut _5: bool;
+      let mut _6: bool;
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _2;
+-         _3 = BitOr(move _4, const true);
++         _3 = const true;
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+          _6 = _1;
+-         _5 = BitAnd(move _6, const false);
++         _5 = const false;
+          StorageDead(_6);
+-         _0 = BitAnd(move _3, move _5);
++         _0 = const false;
+          StorageDead(_5);
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff
new file mode 100644
index 00000000000..6c612d46725
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u8;
+      let mut _2: [u8; 5000];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u8; 5000];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff
new file mode 100644
index 00000000000..87024da2628
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u8;
+      let mut _2: [u8; 5000];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u8; 5000];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff
new file mode 100644
index 00000000000..6c612d46725
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u8;
+      let mut _2: [u8; 5000];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u8; 5000];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff
new file mode 100644
index 00000000000..87024da2628
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -0,0 +1,39 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u8;
+      let mut _2: [u8; 5000];
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = [const 0_u8; 5000];
+          StorageLive(_3);
+          _3 = const 2_usize;
+-         _4 = Len(_2);
+-         _5 = Lt(_3, _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = _2[_3];
++         _1 = _2[2 of 3];
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs
new file mode 100644
index 00000000000..af13c7d1020
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs
@@ -0,0 +1,9 @@
+// unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR large_array_index.main.DataflowConstProp.diff
+fn main() {
+    // check that we don't propagate this, because it's too large
+    let x: u8 = [0_u8; 5000][2];
+}
diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs
new file mode 100644
index 00000000000..dbea1480445
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs
@@ -0,0 +1,10 @@
+// unit-test: DataflowConstProp
+
+// EMIT_MIR mult_by_zero.test.DataflowConstProp.diff
+fn test(x : i32) -> i32 {
+  x * 0
+}
+
+fn main() {
+    test(10);
+}
diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff
new file mode 100644
index 00000000000..91bc10a562f
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff
@@ -0,0 +1,18 @@
+- // MIR for `test` before DataflowConstProp
++ // MIR for `test` after DataflowConstProp
+  
+  fn test(_1: i32) -> i32 {
+      debug x => _1;
+      let mut _0: i32;
+      let mut _2: i32;
+  
+      bb0: {
+          StorageLive(_2);
+          _2 = _1;
+-         _0 = Mul(move _2, const 0_i32);
++         _0 = const 0_i32;
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff
new file mode 100644
index 00000000000..c61414b6541
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff
@@ -0,0 +1,76 @@
+- // MIR for `concrete` before DataflowConstProp
++ // MIR for `concrete` after DataflowConstProp
+  
+  fn concrete() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug x => _1;
+          let _3: usize;
+          scope 2 {
+              debug y => _3;
+              let _5: usize;
+              scope 3 {
+                  debug z0 => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug z1 => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = OffsetOf(Alpha, [0]);
+-         _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
++         _2 = const 4_usize;
++         _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = OffsetOf(Alpha, [1]);
+-         _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
++         _4 = const 0_usize;
++         _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Alpha, [2, 0]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
++         _6 = const 2_usize;
++         _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Alpha, [2, 1]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
++         _8 = const 3_usize;
++         _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff
new file mode 100644
index 00000000000..0c3939a3456
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff
@@ -0,0 +1,76 @@
+- // MIR for `concrete` before DataflowConstProp
++ // MIR for `concrete` after DataflowConstProp
+  
+  fn concrete() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug x => _1;
+          let _3: usize;
+          scope 2 {
+              debug y => _3;
+              let _5: usize;
+              scope 3 {
+                  debug z0 => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug z1 => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = OffsetOf(Alpha, [0]);
+-         _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
++         _2 = const 4_usize;
++         _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = OffsetOf(Alpha, [1]);
+-         _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
++         _4 = const 0_usize;
++         _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Alpha, [2, 0]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
++         _6 = const 2_usize;
++         _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Alpha, [2, 1]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
++         _8 = const 3_usize;
++         _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff
new file mode 100644
index 00000000000..d54d4687060
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff
@@ -0,0 +1,72 @@
+- // MIR for `generic` before DataflowConstProp
++ // MIR for `generic` after DataflowConstProp
+  
+  fn generic() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug gx => _1;
+          let _3: usize;
+          scope 2 {
+              debug gy => _3;
+              let _5: usize;
+              scope 3 {
+                  debug dx => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug dy => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = OffsetOf(Gamma<T>, [0]);
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = OffsetOf(Gamma<T>, [1]);
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Delta<T>, [1]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Delta<T>, [2]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff
new file mode 100644
index 00000000000..6032a2274ef
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff
@@ -0,0 +1,72 @@
+- // MIR for `generic` before DataflowConstProp
++ // MIR for `generic` after DataflowConstProp
+  
+  fn generic() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug gx => _1;
+          let _3: usize;
+          scope 2 {
+              debug gy => _3;
+              let _5: usize;
+              scope 3 {
+                  debug dx => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug dy => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = OffsetOf(Gamma<T>, [0]);
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = OffsetOf(Gamma<T>, [1]);
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Delta<T>, [1]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Delta<T>, [2]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs
new file mode 100644
index 00000000000..ccc90790e52
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs
@@ -0,0 +1,49 @@
+// unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+
+#![feature(offset_of)]
+
+use std::marker::PhantomData;
+use std::mem::offset_of;
+
+struct Alpha {
+    x: u8,
+    y: u16,
+    z: Beta,
+}
+
+struct Beta(u8, u8);
+
+struct Gamma<T> {
+    x: u8,
+    y: u16,
+    _t: T,
+}
+
+#[repr(C)]
+struct Delta<T> {
+    _phantom: PhantomData<T>,
+    x: u8,
+    y: u16,
+}
+
+// EMIT_MIR offset_of.concrete.DataflowConstProp.diff
+fn concrete() {
+    let x = offset_of!(Alpha, x);
+    let y = offset_of!(Alpha, y);
+    let z0 = offset_of!(Alpha, z.0);
+    let z1 = offset_of!(Alpha, z.1);
+}
+
+// EMIT_MIR offset_of.generic.DataflowConstProp.diff
+fn generic<T>() {
+    let gx = offset_of!(Gamma<T>, x);
+    let gy = offset_of!(Gamma<T>, y);
+    let dx = offset_of!(Delta<T>, x);
+    let dy = offset_of!(Delta<T>, y);
+}
+
+fn main() {
+    concrete();
+    generic::<()>();
+}
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff
new file mode 100644
index 00000000000..a18ef6c9db7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff
@@ -0,0 +1,43 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: u32;
+      let mut _3: [u32; 8];
+      let _4: usize;
+      let mut _5: usize;
+      let mut _6: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = [const 42_u32; 8];
+          StorageLive(_4);
+          _4 = const 2_usize;
+-         _5 = Len(_3);
+-         _6 = Lt(_4, _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _2 = _3[_4];
++         _2 = _3[2 of 3];
+          _1 = Add(move _2, const 0_u32);
+          StorageDead(_2);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff
new file mode 100644
index 00000000000..3356ef98b14
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -0,0 +1,43 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: u32;
+      let mut _3: [u32; 8];
+      let _4: usize;
+      let mut _5: usize;
+      let mut _6: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = [const 42_u32; 8];
+          StorageLive(_4);
+          _4 = const 2_usize;
+-         _5 = Len(_3);
+-         _6 = Lt(_4, _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _2 = _3[_4];
++         _2 = _3[2 of 3];
+          _1 = Add(move _2, const 0_u32);
+          StorageDead(_2);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff
new file mode 100644
index 00000000000..a18ef6c9db7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff
@@ -0,0 +1,43 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: u32;
+      let mut _3: [u32; 8];
+      let _4: usize;
+      let mut _5: usize;
+      let mut _6: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = [const 42_u32; 8];
+          StorageLive(_4);
+          _4 = const 2_usize;
+-         _5 = Len(_3);
+-         _6 = Lt(_4, _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _2 = _3[_4];
++         _2 = _3[2 of 3];
+          _1 = Add(move _2, const 0_u32);
+          StorageDead(_2);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff
new file mode 100644
index 00000000000..3356ef98b14
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -0,0 +1,43 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: u32;
+      let mut _3: [u32; 8];
+      let _4: usize;
+      let mut _5: usize;
+      let mut _6: bool;
+      scope 1 {
+          debug x => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = [const 42_u32; 8];
+          StorageLive(_4);
+          _4 = const 2_usize;
+-         _5 = Len(_3);
+-         _6 = Lt(_4, _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _2 = _3[_4];
++         _2 = _3[2 of 3];
+          _1 = Add(move _2, const 0_u32);
+          StorageDead(_2);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs
new file mode 100644
index 00000000000..9fa353e44c5
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/repeat.rs
@@ -0,0 +1,8 @@
+// unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR repeat.main.DataflowConstProp.diff
+fn main() {
+    let x: u32 = [42; 8][2] + 0;
+}
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
new file mode 100644
index 00000000000..be55d259dcf
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
@@ -0,0 +1,76 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const _;
+          _4 = _14;
+          _3 = _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(_6, _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = (*_2)[_6];
++         _1 = (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const _;
+          StorageLive(_11);
+          _11 = const 1_usize;
+          _12 = Len((*_10));
+-         _13 = Lt(_11, _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable];
++         _13 = Lt(const 1_usize, _12);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+-         _9 = (*_10)[_11];
++         _9 = (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
new file mode 100644
index 00000000000..f9a6c509ac8
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -0,0 +1,76 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const _;
+          _4 = _14;
+          _3 = _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(_6, _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = (*_2)[_6];
++         _1 = (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const _;
+          StorageLive(_11);
+          _11 = const 1_usize;
+          _12 = Len((*_10));
+-         _13 = Lt(_11, _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue];
++         _13 = Lt(const 1_usize, _12);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue];
+      }
+  
+      bb2: {
+-         _9 = (*_10)[_11];
++         _9 = (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
new file mode 100644
index 00000000000..be55d259dcf
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
@@ -0,0 +1,76 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const _;
+          _4 = _14;
+          _3 = _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(_6, _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = (*_2)[_6];
++         _1 = (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const _;
+          StorageLive(_11);
+          _11 = const 1_usize;
+          _12 = Len((*_10));
+-         _13 = Lt(_11, _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable];
++         _13 = Lt(const 1_usize, _12);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+-         _9 = (*_10)[_11];
++         _9 = (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
new file mode 100644
index 00000000000..f9a6c509ac8
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -0,0 +1,76 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const _;
+          _4 = _14;
+          _3 = _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(_6, _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = (*_2)[_6];
++         _1 = (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const _;
+          StorageLive(_11);
+          _11 = const 1_usize;
+          _12 = Len((*_10));
+-         _13 = Lt(_11, _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue];
++         _13 = Lt(const 1_usize, _12);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue];
+      }
+  
+      bb2: {
+-         _9 = (*_10)[_11];
++         _9 = (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs
new file mode 100644
index 00000000000..41367e48497
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs
@@ -0,0 +1,12 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// unit-test: DataflowConstProp
+// compile-flags: -Zmir-enable-passes=+InstSimplify
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR slice_len.main.DataflowConstProp.diff
+fn main() {
+    let local = (&[1u32, 2, 3] as &[u32])[1];
+
+    const SLICE: &[u32] = &[1, 2, 3];
+    let constant = SLICE[1];
+}
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..52f096ac0e4
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `from_char` before DataflowConstProp
++ // MIR for `from_char` after DataflowConstProp
+  
+  fn from_char() -> i32 {
+      let mut _0: i32;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 'R' as i32 (Transmute);
++         _0 = const 82_i32;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..52f096ac0e4
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `from_char` before DataflowConstProp
++ // MIR for `from_char` after DataflowConstProp
+  
+  fn from_char() -> i32 {
+      let mut _0: i32;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 'R' as i32 (Transmute);
++         _0 = const 82_i32;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..3972eb209a1
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_bool` before DataflowConstProp
++ // MIR for `invalid_bool` after DataflowConstProp
+  
+  fn invalid_bool() -> bool {
+      let mut _0: bool;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const -1_i8 as bool (Transmute);
++         _0 = const {transmute(0xff): bool};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..3972eb209a1
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_bool` before DataflowConstProp
++ // MIR for `invalid_bool` after DataflowConstProp
+  
+  fn invalid_bool() -> bool {
+      let mut _0: bool;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const -1_i8 as bool (Transmute);
++         _0 = const {transmute(0xff): bool};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..837dabde42a
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_char` before DataflowConstProp
++ // MIR for `invalid_char` after DataflowConstProp
+  
+  fn invalid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const _ as char (Transmute);
++         _0 = const {transmute(0x7fffffff): char};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..837dabde42a
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_char` before DataflowConstProp
++ // MIR for `invalid_char` after DataflowConstProp
+  
+  fn invalid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const _ as char (Transmute);
++         _0 = const {transmute(0x7fffffff): char};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..6091e169e8e
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
@@ -0,0 +1,18 @@
+- // MIR for `less_as_i8` before DataflowConstProp
++ // MIR for `less_as_i8` after DataflowConstProp
+  
+  fn less_as_i8() -> i8 {
+      let mut _0: i8;
+      let mut _1: std::cmp::Ordering;
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = Less;
+          _0 = move _1 as i8 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..6091e169e8e
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
@@ -0,0 +1,18 @@
+- // MIR for `less_as_i8` before DataflowConstProp
++ // MIR for `less_as_i8` after DataflowConstProp
+  
+  fn less_as_i8() -> i8 {
+      let mut _0: i8;
+      let mut _1: std::cmp::Ordering;
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = Less;
+          _0 = move _1 as i8 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs
new file mode 100644
index 00000000000..c25e33ab0b6
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.rs
@@ -0,0 +1,63 @@
+// unit-test: DataflowConstProp
+// compile-flags: -O --crate-type=lib
+// ignore-endian-big
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+use std::mem::transmute;
+
+// EMIT_MIR transmute.less_as_i8.DataflowConstProp.diff
+pub fn less_as_i8() -> i8 {
+    unsafe { transmute(std::cmp::Ordering::Less) }
+}
+
+// EMIT_MIR transmute.from_char.DataflowConstProp.diff
+pub fn from_char() -> i32 {
+    unsafe { transmute('R') }
+}
+
+// EMIT_MIR transmute.valid_char.DataflowConstProp.diff
+pub fn valid_char() -> char {
+    unsafe { transmute(0x52_u32) }
+}
+
+// EMIT_MIR transmute.invalid_char.DataflowConstProp.diff
+pub unsafe fn invalid_char() -> char {
+    unsafe { transmute(i32::MAX) }
+}
+
+// EMIT_MIR transmute.invalid_bool.DataflowConstProp.diff
+pub unsafe fn invalid_bool() -> bool {
+    unsafe { transmute(-1_i8) }
+}
+
+// EMIT_MIR transmute.undef_union_as_integer.DataflowConstProp.diff
+pub unsafe fn undef_union_as_integer() -> u32 {
+    union Union32 { value: u32, unit: () }
+    unsafe { transmute(Union32 { unit: () }) }
+}
+
+// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
+pub unsafe fn unreachable_direct() -> ! {
+    let x: Never = unsafe { transmute(()) };
+    match x {}
+}
+
+// EMIT_MIR transmute.unreachable_ref.DataflowConstProp.diff
+pub unsafe fn unreachable_ref() -> ! {
+    let x: &Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_mut.DataflowConstProp.diff
+pub unsafe fn unreachable_mut() -> ! {
+    let x: &mut Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_box.DataflowConstProp.diff
+pub unsafe fn unreachable_box() -> ! {
+    let x: Box<Never> = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+enum Never {}
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..fc0634b1f8f
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `undef_union_as_integer` before DataflowConstProp
++ // MIR for `undef_union_as_integer` after DataflowConstProp
+  
+  fn undef_union_as_integer() -> u32 {
+      let mut _0: u32;
+      let mut _1: undef_union_as_integer::Union32;
+      let mut _2: ();
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = Union32 { value: move _2 };
+          StorageDead(_2);
+          _0 = move _1 as u32 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..fc0634b1f8f
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `undef_union_as_integer` before DataflowConstProp
++ // MIR for `undef_union_as_integer` after DataflowConstProp
+  
+  fn undef_union_as_integer() -> u32 {
+      let mut _0: u32;
+      let mut _1: undef_union_as_integer::Union32;
+      let mut _2: ();
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = Union32 { value: move _2 };
+          StorageDead(_2);
+          _0 = move _1 as u32 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..d0c298ba233
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_box` before DataflowConstProp
++ // MIR for `unreachable_box` after DataflowConstProp
+  
+  fn unreachable_box() -> ! {
+      let mut _0: !;
+      let _1: std::boxed::Box<Never>;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
++         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..d0c298ba233
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_box` before DataflowConstProp
++ // MIR for `unreachable_box` after DataflowConstProp
+  
+  fn unreachable_box() -> ! {
+      let mut _0: !;
+      let _1: std::boxed::Box<Never>;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
++         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..acbb5cd1bc7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `unreachable_direct` before DataflowConstProp
++ // MIR for `unreachable_direct` after DataflowConstProp
+  
+  fn unreachable_direct() -> ! {
+      let mut _0: !;
+      let _1: Never;
+      let mut _2: ();
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = move _2 as Never (Transmute);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..acbb5cd1bc7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `unreachable_direct` before DataflowConstProp
++ // MIR for `unreachable_direct` after DataflowConstProp
+  
+  fn unreachable_direct() -> ! {
+      let mut _0: !;
+      let _1: Never;
+      let mut _2: ();
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = move _2 as Never (Transmute);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..2ffaeea72db
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
@@ -0,0 +1,24 @@
+- // MIR for `unreachable_mut` before DataflowConstProp
++ // MIR for `unreachable_mut` after DataflowConstProp
+  
+  fn unreachable_mut() -> ! {
+      let mut _0: !;
+      let _1: &mut Never;
+      let mut _2: &mut Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = const 1_usize as &mut Never (Transmute);
++         _2 = const {0x1 as &mut Never};
+          _1 = &mut (*_2);
+          StorageDead(_2);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..2ffaeea72db
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
@@ -0,0 +1,24 @@
+- // MIR for `unreachable_mut` before DataflowConstProp
++ // MIR for `unreachable_mut` after DataflowConstProp
+  
+  fn unreachable_mut() -> ! {
+      let mut _0: !;
+      let _1: &mut Never;
+      let mut _2: &mut Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = const 1_usize as &mut Never (Transmute);
++         _2 = const {0x1 as &mut Never};
+          _1 = &mut (*_2);
+          StorageDead(_2);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..31fcaafc5bc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_ref` before DataflowConstProp
++ // MIR for `unreachable_ref` after DataflowConstProp
+  
+  fn unreachable_ref() -> ! {
+      let mut _0: !;
+      let _1: &Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as &Never (Transmute);
++         _1 = const {0x1 as &Never};
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..31fcaafc5bc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_ref` before DataflowConstProp
++ // MIR for `unreachable_ref` after DataflowConstProp
+  
+  fn unreachable_ref() -> ! {
+      let mut _0: !;
+      let _1: &Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as &Never (Transmute);
++         _1 = const {0x1 as &Never};
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..402ef754a64
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `valid_char` before DataflowConstProp
++ // MIR for `valid_char` after DataflowConstProp
+  
+  fn valid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 82_u32 as char (Transmute);
++         _0 = const 'R';
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..402ef754a64
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `valid_char` before DataflowConstProp
++ // MIR for `valid_char` after DataflowConstProp
+  
+  fn valid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 82_u32 as char (Transmute);
++         _0 = const 'R';
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 6b4f4c80560..79fd9457ce1 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -9,7 +9,7 @@ use core::num::flt2dec;
 use std::fmt::{Formatter, Result};
 
 // EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
-fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
+pub fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
 where
     T: flt2dec::DecodableFloat,
 {
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
index 958078b9706..acbb7904985 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: std::string::String,
+            ty: Adt(
+                std::string::String,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
index 7e050e585b1..c17d4421542 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: std::string::String,
+            ty: Adt(
+                std::string::String,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index 13d703b908c..e33f5f59de1 100644
--- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -2,7 +2,11 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: HasDrop,
+            ty: Adt(
+                HasDrop,
+                [
+                ],
+            ),
             source_info: SourceInfo {
                 span: $DIR/generator_tiny.rs:20:13: 20:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
index f61632728ba..9d8f272abea 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
@@ -33,12 +33,10 @@
           _3 = &_4;
           _2 = move _3 as &[T] (PointerCoercion(Unsize));
           StorageDead(_3);
-          _8 = Len((*_2));
+          _8 = const 3_usize;
           _9 = const 3_usize;
--         _10 = Eq(move _8, const 3_usize);
--         switchInt(move _10) -> [0: bb1, otherwise: bb2];
-+         nop;
-+         switchInt(move _8) -> [3: bb2, otherwise: bb1];
+          _10 = const true;
+          goto -> bb2;
       }
   
       bb1: {
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
index f6c337be10f..738b0b1b3e5 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
@@ -33,12 +33,10 @@
           _3 = &_4;
           _2 = move _3 as &[T] (PointerCoercion(Unsize));
           StorageDead(_3);
-          _8 = Len((*_2));
+          _8 = const 3_usize;
           _9 = const 3_usize;
--         _10 = Eq(move _8, const 3_usize);
--         switchInt(move _10) -> [0: bb1, otherwise: bb2];
-+         nop;
-+         switchInt(move _8) -> [3: bb2, otherwise: bb1];
+          _10 = const true;
+          goto -> bb2;
       }
   
       bb1: {
diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index f12179a8905..b6a673b6355 100644
--- a/tests/mir-opt/issue_99325.main.built.after.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
new file mode 100644
index 00000000000..9d112cfa20a
--- /dev/null
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -0,0 +1,276 @@
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+|
+fn main() -> () {
+    let mut _0: ();
+    let _1: ();
+    let mut _2: (&&[u8], &&[u8; 4]);
+    let mut _3: &&[u8];
+    let _4: &[u8];
+    let mut _5: &&[u8; 4];
+    let _6: &[u8; 4];
+    let _7: [u8; 4];
+    let _8: &&[u8];
+    let _9: &&[u8; 4];
+    let mut _10: bool;
+    let mut _11: &&[u8];
+    let mut _12: &&[u8; 4];
+    let mut _13: !;
+    let _15: !;
+    let mut _16: core::panicking::AssertKind;
+    let mut _17: &&[u8];
+    let _18: &&[u8];
+    let mut _19: &&[u8; 4];
+    let _20: &&[u8; 4];
+    let mut _21: std::option::Option<std::fmt::Arguments<'_>>;
+    let _22: ();
+    let mut _23: (&&[u8], &&[u8; 4]);
+    let mut _24: &&[u8];
+    let _25: &[u8];
+    let mut _26: &&[u8; 4];
+    let _27: &[u8; 4];
+    let _28: &&[u8];
+    let _29: &&[u8; 4];
+    let mut _30: bool;
+    let mut _31: &&[u8];
+    let mut _32: &&[u8; 4];
+    let mut _33: !;
+    let _35: !;
+    let mut _36: core::panicking::AssertKind;
+    let mut _37: &&[u8];
+    let _38: &&[u8];
+    let mut _39: &&[u8; 4];
+    let _40: &&[u8; 4];
+    let mut _41: std::option::Option<std::fmt::Arguments<'_>>;
+    scope 1 {
+        debug left_val => _8;
+        debug right_val => _9;
+        let _14: core::panicking::AssertKind;
+        scope 2 {
+            debug kind => _14;
+        }
+    }
+    scope 3 {
+        debug left_val => _28;
+        debug right_val => _29;
+        let _34: core::panicking::AssertKind;
+        scope 4 {
+            debug kind => _34;
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);
+        StorageLive(_2);
+        StorageLive(_3);
+        StorageLive(_4);
+        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb21];
+    }
+
+    bb1: {
+        _3 = &_4;
+        StorageLive(_5);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8];
+        _6 = &_7;
+        _5 = &_6;
+        _2 = (move _3, move _5);
+        StorageDead(_5);
+        StorageDead(_3);
+        FakeRead(ForMatchedPlace(None), _2);
+        StorageLive(_8);
+        _8 = (_2.0: &&[u8]);
+        StorageLive(_9);
+        _9 = (_2.1: &&[u8; 4]);
+        StorageLive(_10);
+        StorageLive(_11);
+        _11 = &(*_8);
+        StorageLive(_12);
+        _12 = &(*_9);
+        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb2, unwind: bb21];
+    }
+
+    bb2: {
+        switchInt(move _10) -> [0: bb4, otherwise: bb3];
+    }
+
+    bb3: {
+        StorageDead(_12);
+        StorageDead(_11);
+        goto -> bb8;
+    }
+
+    bb4: {
+        goto -> bb5;
+    }
+
+    bb5: {
+        StorageDead(_12);
+        StorageDead(_11);
+        StorageLive(_14);
+        _14 = core::panicking::AssertKind::Eq;
+        FakeRead(ForLet(None), _14);
+        StorageLive(_15);
+        StorageLive(_16);
+        _16 = move _14;
+        StorageLive(_17);
+        StorageLive(_18);
+        _18 = &(*_8);
+        _17 = &(*_18);
+        StorageLive(_19);
+        StorageLive(_20);
+        _20 = &(*_9);
+        _19 = &(*_20);
+        StorageLive(_21);
+        _21 = Option::<Arguments<'_>>::None;
+        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb21;
+    }
+
+    bb6: {
+        StorageDead(_21);
+        StorageDead(_19);
+        StorageDead(_17);
+        StorageDead(_16);
+        StorageDead(_20);
+        StorageDead(_18);
+        StorageDead(_15);
+        StorageDead(_14);
+        unreachable;
+    }
+
+    bb7: {
+        goto -> bb9;
+    }
+
+    bb8: {
+        _1 = const ();
+        goto -> bb9;
+    }
+
+    bb9: {
+        StorageDead(_10);
+        StorageDead(_9);
+        StorageDead(_8);
+        goto -> bb10;
+    }
+
+    bb10: {
+        StorageDead(_7);
+        StorageDead(_6);
+        StorageDead(_4);
+        StorageDead(_2);
+        StorageDead(_1);
+        StorageLive(_22);
+        StorageLive(_23);
+        StorageLive(_24);
+        StorageLive(_25);
+        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb11, unwind: bb21];
+    }
+
+    bb11: {
+        _24 = &_25;
+        StorageLive(_26);
+        StorageLive(_27);
+        _27 = const b"AAAA";
+        _26 = &_27;
+        _23 = (move _24, move _26);
+        StorageDead(_26);
+        StorageDead(_24);
+        FakeRead(ForMatchedPlace(None), _23);
+        StorageLive(_28);
+        _28 = (_23.0: &&[u8]);
+        StorageLive(_29);
+        _29 = (_23.1: &&[u8; 4]);
+        StorageLive(_30);
+        StorageLive(_31);
+        _31 = &(*_28);
+        StorageLive(_32);
+        _32 = &(*_29);
+        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb12, unwind: bb21];
+    }
+
+    bb12: {
+        switchInt(move _30) -> [0: bb14, otherwise: bb13];
+    }
+
+    bb13: {
+        StorageDead(_32);
+        StorageDead(_31);
+        goto -> bb18;
+    }
+
+    bb14: {
+        goto -> bb15;
+    }
+
+    bb15: {
+        StorageDead(_32);
+        StorageDead(_31);
+        StorageLive(_34);
+        _34 = core::panicking::AssertKind::Eq;
+        FakeRead(ForLet(None), _34);
+        StorageLive(_35);
+        StorageLive(_36);
+        _36 = move _34;
+        StorageLive(_37);
+        StorageLive(_38);
+        _38 = &(*_28);
+        _37 = &(*_38);
+        StorageLive(_39);
+        StorageLive(_40);
+        _40 = &(*_29);
+        _39 = &(*_40);
+        StorageLive(_41);
+        _41 = Option::<Arguments<'_>>::None;
+        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb21;
+    }
+
+    bb16: {
+        StorageDead(_41);
+        StorageDead(_39);
+        StorageDead(_37);
+        StorageDead(_36);
+        StorageDead(_40);
+        StorageDead(_38);
+        StorageDead(_35);
+        StorageDead(_34);
+        unreachable;
+    }
+
+    bb17: {
+        goto -> bb19;
+    }
+
+    bb18: {
+        _22 = const ();
+        goto -> bb19;
+    }
+
+    bb19: {
+        StorageDead(_30);
+        StorageDead(_29);
+        StorageDead(_28);
+        goto -> bb20;
+    }
+
+    bb20: {
+        StorageDead(_27);
+        StorageDead(_25);
+        StorageDead(_23);
+        StorageDead(_22);
+        _0 = const ();
+        return;
+    }
+
+    bb21 (cleanup): {
+        resume;
+    }
+}
+
+alloc4 (size: 4, align: 1) {
+    41 41 41 41                                     │ AAAA
+}
diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs
index fe819cddb2c..3603228a502 100644
--- a/tests/mir-opt/issue_99325.rs
+++ b/tests/mir-opt/issue_99325.rs
@@ -1,3 +1,5 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 #![feature(adt_const_params)]
 #![allow(incomplete_features)]
 
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
index 8dd2cd7900f..2fd669aeeb6 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
@@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
     let mut _4: usize;
     scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
         debug self => _1;
-        debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
+        debug ((index: std::ops::Range<usize>).0: usize) => _3;
+        debug ((index: std::ops::Range<usize>).1: usize) => _4;
         let mut _5: *mut [u32];
         let mut _13: *mut [u32];
         scope 2 {
             scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
-                debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
+                debug ((self: std::ops::Range<usize>).0: usize) => _3;
+                debug ((self: std::ops::Range<usize>).1: usize) => _4;
                 debug slice => _5;
                 let mut _7: *mut u32;
                 let mut _8: *mut u32;
                 let _15: usize;
                 let _16: usize;
                 scope 4 {
-                    debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
+                    debug ((this: std::ops::Range<usize>).0: usize) => _15;
+                    debug ((this: std::ops::Range<usize>).1: usize) => _16;
                     scope 5 {
                         let _6: usize;
                         scope 6 {
@@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                             }
                         }
                         scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
-                            debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
+                            debug ((this: std::ops::Range<usize>).0: usize) => _15;
+                            debug ((this: std::ops::Range<usize>).1: usize) => _16;
                             debug slice => _5;
                             scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
                                 debug self => _5;
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
index 8dd2cd7900f..2fd669aeeb6 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
@@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
     let mut _4: usize;
     scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
         debug self => _1;
-        debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
+        debug ((index: std::ops::Range<usize>).0: usize) => _3;
+        debug ((index: std::ops::Range<usize>).1: usize) => _4;
         let mut _5: *mut [u32];
         let mut _13: *mut [u32];
         scope 2 {
             scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
-                debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
+                debug ((self: std::ops::Range<usize>).0: usize) => _3;
+                debug ((self: std::ops::Range<usize>).1: usize) => _4;
                 debug slice => _5;
                 let mut _7: *mut u32;
                 let mut _8: *mut u32;
                 let _15: usize;
                 let _16: usize;
                 scope 4 {
-                    debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
+                    debug ((this: std::ops::Range<usize>).0: usize) => _15;
+                    debug ((this: std::ops::Range<usize>).1: usize) => _16;
                     scope 5 {
                         let _6: usize;
                         scope 6 {
@@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
                             }
                         }
                         scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
-                            debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
+                            debug ((this: std::ops::Range<usize>).0: usize) => _15;
+                            debug ((this: std::ops::Range<usize>).1: usize) => _16;
                             debug slice => _5;
                             scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
                                 debug self => _5;
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
index bb14b909a95..b020d1baafa 100644
--- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -33,7 +33,8 @@
 +     let _32: u32;
       scope 1 {
 -         debug foo => _1;
-+         debug foo => Foo<T>{ .0 => _31, .1 => _32, };
++         debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _31;
++         debug ((foo: Foo<T>).1: u32) => _32;
           let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
           scope 2 {
               debug x => _5;
diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
index 7ee0431692c..1330f9b3ac8 100644
--- a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
@@ -8,7 +8,8 @@
 +     let _5: u8;
       scope 1 {
 -         debug y => _1;
-+         debug y => (usize, u8){ .0 => _4, .1 => _5, };
++         debug ((y: (usize, u8)).0: usize) => _4;
++         debug ((y: (usize, u8)).1: u8) => _5;
           let _2: usize;
           scope 2 {
               debug t => _2;
diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
index 0a1de891aee..3621338635e 100644
--- a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
@@ -11,7 +11,10 @@
 +     let _14: std::option::Option<isize>;
       scope 1 {
 -         debug y => _2;
-+         debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, };
++         debug ((y: Foo).0: u8) => _11;
++         debug ((y: Foo).1: ()) => _12;
++         debug ((y: Foo).2: &str) => _13;
++         debug ((y: Foo).3: std::option::Option<isize>) => _14;
           let _3: u8;
           scope 2 {
               debug t => _3;
@@ -25,7 +28,10 @@
 +                 let _10: std::option::Option<isize>;
                   scope 4 {
 -                     debug z => _5;
-+                     debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, };
++                     debug ((z: Foo).0: u8) => _7;
++                     debug ((z: Foo).1: ()) => _8;
++                     debug ((z: Foo).2: &str) => _9;
++                     debug ((z: Foo).3: std::option::Option<isize>) => _10;
                       let _6: ();
                       scope 5 {
                           debug a => _6;
diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
index d7c57c293c4..304bf2fb1a7 100644
--- a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
@@ -11,7 +11,10 @@
 +     let _8: std::option::Option<isize>;
       scope 1 {
 -         debug y => _2;
-+         debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, };
++         debug ((y: Foo).0: u8) => _5;
++         debug ((y: Foo).1: ()) => _6;
++         debug ((y: Foo).2: &str) => _7;
++         debug ((y: Foo).3: std::option::Option<isize>) => _8;
           let _3: u8;
           scope 2 {
               debug t => _3;
diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs
index 68132638759..1c9d33dcc8e 100644
--- a/tests/run-make-fulldeps/issue-19371/foo.rs
+++ b/tests/run-make-fulldeps/issue-19371/foo.rs
@@ -61,6 +61,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         override_queries: None,
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
+        expanded_args: Default::default(),
     };
 
     interface::run_compiler(config, |compiler| {
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 04c551cf4bb..b59a65a713f 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries};
 use rustc_middle::query::queries::mir_borrowck::ProvidedValue;
 use rustc_middle::query::{ExternProviders, Providers};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::{Session, EarlyErrorHandler};
+use rustc_session::Session;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::thread_local;
@@ -58,7 +58,6 @@ impl rustc_driver::Callbacks for CompilerCalls {
     // the result.
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         compiler: &Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/tests/run-make/compressed-debuginfo/Makefile b/tests/run-make/compressed-debuginfo/Makefile
new file mode 100644
index 00000000000..f9e4927d008
--- /dev/null
+++ b/tests/run-make/compressed-debuginfo/Makefile
@@ -0,0 +1,15 @@
+# ignore-cross-compile
+include ../tools.mk
+
+# only-linux
+# min-llvm-version: 16.0
+#
+# This tests debuginfo-compression.
+
+all: zlib zstandard
+
+zlib:
+	test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zlib foo.rs 2>&1 | sed 's/.*unknown.*zlib.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZLIB
+
+zstandard:
+	test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zstd foo.rs 2>&1 | sed 's/.*unknown.*zstd.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZST
diff --git a/tests/run-make/compressed-debuginfo/foo.rs b/tests/run-make/compressed-debuginfo/foo.rs
new file mode 100644
index 00000000000..185ce22450c
--- /dev/null
+++ b/tests/run-make/compressed-debuginfo/foo.rs
@@ -0,0 +1,3 @@
+pub fn foo() -> i32 {
+    42
+}
diff --git a/tests/run-make/lto-linkage-used-attr/Makefile b/tests/run-make/lto-linkage-used-attr/Makefile
new file mode 100644
index 00000000000..e78b83890ed
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/Makefile
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+# Verify that the impl_* symbols are preserved. #108030
+# only-x86_64-unknown-linux-gnu
+# min-llvm-version: 17
+
+all:
+	$(RUSTC) -Cdebuginfo=0 -Copt-level=3 lib.rs
+	$(RUSTC) -Clto=fat -Cdebuginfo=0 -Copt-level=3 main.rs
diff --git a/tests/run-make/lto-linkage-used-attr/lib.rs b/tests/run-make/lto-linkage-used-attr/lib.rs
new file mode 100644
index 00000000000..0a92ea9cd22
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/lib.rs
@@ -0,0 +1,50 @@
+#![crate_type = "rlib"]
+#![crate_type = "cdylib"]
+
+#[macro_export]
+macro_rules! asm_func {
+    ($name:expr, $body:expr $(, $($args:tt)*)?) => {
+        core::arch::global_asm!(
+            concat!(
+                ".p2align 4\n",
+                ".hidden ", $name, "\n",
+                ".global ", $name, "\n",
+                ".type ", $name, ",@function\n",
+                $name, ":\n",
+                $body,
+                ".size ", $name, ",.-", $name,
+            )
+            $(, $($args)*)?
+        );
+    };
+}
+
+macro_rules! libcall_trampoline {
+    ($libcall:ident ; $libcall_impl:ident) => {
+        asm_func!(
+            stringify!($libcall),
+            concat!(
+                "
+                   .cfi_startproc simple
+                   .cfi_def_cfa_offset 0
+                    jmp {}
+                    .cfi_endproc
+                ",
+            ),
+            sym $libcall_impl
+        );
+    };
+}
+
+pub mod trampolines {
+    extern "C" {
+        pub fn table_fill_funcref();
+        pub fn table_fill_externref();
+    }
+
+    unsafe extern "C" fn impl_table_fill_funcref() {}
+    unsafe extern "C" fn impl_table_fill_externref() {}
+
+    libcall_trampoline!(table_fill_funcref ; impl_table_fill_funcref);
+    libcall_trampoline!(table_fill_externref ; impl_table_fill_externref);
+}
diff --git a/tests/run-make/lto-linkage-used-attr/main.rs b/tests/run-make/lto-linkage-used-attr/main.rs
new file mode 100644
index 00000000000..256b02e5b0b
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/main.rs
@@ -0,0 +1,10 @@
+extern crate lib;
+
+use lib::trampolines::*;
+
+fn main() {
+    unsafe {
+        table_fill_externref();
+        table_fill_funcref();
+    }
+}
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/Makefile b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile
new file mode 100644
index 00000000000..a7be301a5b0
--- /dev/null
+++ b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile
@@ -0,0 +1,16 @@
+include ../tools.mk
+
+# only-windows-msvc
+
+# tests if the pdb contains the following information in the LF_BUILDINFO:
+# 1. the commandline args to compile it (cmd)
+# 2. full path to the compiler (cl)
+
+# we just do a stringsearch on the pdb, as these need to show up at least once, as the LF_BUILDINFO is created for each cgu
+# actual parsing would be better, but this is a simple and good enough solution for now
+
+all:
+	$(RUSTC_ORIGINAL) main.rs -g --crate-name my_crate_name --crate-type bin -C metadata=dc9ef878b0a48666 --out-dir $(TMPDIR)
+	cat '$(TMPDIR)/my_crate_name.pdb' | grep -F '$(RUSTC_ORIGINAL)'
+# using a file containing the string so I don't have problems with escaping quotes and spaces 
+	cat '$(TMPDIR)/my_crate_name.pdb' | grep -f 'stringlist.txt'
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/main.rs b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs
new file mode 100644
index 00000000000..f79c691f085
--- /dev/null
+++ b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs
@@ -0,0 +1,2 @@
+fn main() {
+}
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
new file mode 100644
index 00000000000..634e9f19e89
--- /dev/null
+++ b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
@@ -0,0 +1 @@
+"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir"
\ No newline at end of file
diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile
index 654c303b3e2..6b153e5b54e 100644
--- a/tests/run-make/print-cfg/Makefile
+++ b/tests/run-make/print-cfg/Makefile
@@ -13,19 +13,19 @@ all: default output_to_file
 
 output_to_file:
 	# Backend-independent, printed by rustc_driver_impl/src/lib.rs
-	$(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt -Z unstable-options
+	$(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt
 	$(CGREP) windows < $(TMPDIR)/cfg.txt
 
 	# Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs
-	$(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt -Z unstable-options
+	$(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt
 	$(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt
 
 	# Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs
-	$(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt -Z unstable-options
+	$(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt
 	$(CGREP) reference-types < $(TMPDIR)/target-features.txt
 
 	# Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp
-	$(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt -Z unstable-options
+	$(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt
 	$(CGREP) generic < $(TMPDIR)/target-cpus.txt
 
 ifdef IS_WINDOWS
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 6e880302f28..84c20355500 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -33,21 +33,21 @@ define-function: (
 
 call-function: ("check-colors", {
     "theme": "ayu",
-    "color": "rgb(197, 197, 197)",
-    "background": "rgb(49, 69, 89)",
-    "box_shadow": "rgb(92, 103, 115)",
+    "color": "#c5c5c5",
+    "background": "#314559",
+    "box_shadow": "#5c6773",
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "color": "rgb(0, 0, 0)",
-    "background": "rgb(250, 251, 252)",
-    "box_shadow": "rgb(198, 203, 209)",
+    "color": "#000",
+    "background": "#fafbfc",
+    "box_shadow": "#c6cbd1",
 })
 call-function: ("check-colors", {
     "theme": "light",
-    "color": "rgb(0, 0, 0)",
-    "background": "rgb(250, 251, 252)",
-    "box_shadow": "rgb(198, 203, 209)",
+    "color": "#000",
+    "background": "#fafbfc",
+    "box_shadow": "#c6cbd1",
 })
 
 // This test ensures that opening the help popover without switching pages works.
diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml
index 46d1856b4d6..e7c64791256 100644
--- a/tests/rustdoc-gui/search-no-result.goml
+++ b/tests/rustdoc-gui/search-no-result.goml
@@ -21,16 +21,16 @@ define-function: (
 
 call-function: ("check-no-result", {
     "theme": "ayu",
-    "link": "rgb(57, 175, 215)",
-    "link_hover": "rgb(57, 175, 215)",
+    "link": "#39afd7",
+    "link_hover": "#39afd7",
 })
 call-function: ("check-no-result", {
     "theme": "dark",
-    "link": "rgb(210, 153, 29)",
-    "link_hover": "rgb(210, 153, 29)",
+    "link": "#d2991d",
+    "link_hover": "#d2991d",
 })
 call-function: ("check-no-result", {
     "theme": "light",
-    "link": "rgb(56, 115, 173)",
-    "link_hover": "rgb(56, 115, 173)",
+    "link": "#3873ad",
+    "link_hover": "#3873ad",
 })
diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
new file mode 100644
index 00000000000..f4e020b3b95
--- /dev/null
+++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
@@ -0,0 +1,5 @@
+pub struct InlineOne<A> {
+   pub inline: A
+}
+
+pub type InlineU64 = InlineOne<u64>;
diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc/const-generics/const-generic-defaults.rs
index f781c6a62f2..7a0a794112d 100644
--- a/tests/rustdoc/const-generics/const-generic-defaults.rs
+++ b/tests/rustdoc/const-generics/const-generic-defaults.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);'
+//      'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>('
 pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc/const-generics/const-generics-docs.rs
index 828486a41d4..70a9518f05b 100644
--- a/tests/rustdoc/const-generics/const-generics-docs.rs
+++ b/tests/rustdoc/const-generics/const-generics-docs.rs
@@ -33,7 +33,7 @@ impl<const N: usize> Trait<N> for [u8; N] {}
 // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
 //      'pub struct Foo<const N: usize> where u8: Trait<N>'
 pub struct Foo<const N: usize> where u8: Trait<N>;
-// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
+// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>('
 pub struct Bar<T, const N: usize>([T; N]);
 
 // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
@@ -92,7 +92,7 @@ macro_rules! define_me {
 }
 
 // @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Foz<const N: usize>(_);'
+//      'pub struct Foz<const N: usize>(/* private fields */);'
 define_me!(Foz<N>);
 
 trait Q {
diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs
new file mode 100644
index 00000000000..ac486c36ad0
--- /dev/null
+++ b/tests/rustdoc/issue-32077-type-alias-impls.rs
@@ -0,0 +1,66 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/32077>.
+
+#![crate_name = "foo"]
+
+pub struct GenericStruct<T>(T);
+
+impl<T> GenericStruct<T> {
+    pub fn on_gen(arg: T) {}
+}
+
+impl GenericStruct<u32> {
+    pub fn on_u32(arg: u32) {}
+}
+
+pub trait Foo {}
+pub trait Bar {}
+
+impl<T> Foo for GenericStruct<T> {}
+impl Bar for GenericStruct<u32> {}
+
+// @has 'foo/type.TypedefStruct.html'
+// We check that "Aliased type" is also present as a title in the sidebar.
+// @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type'
+// We check that we have the implementation of the type alias itself.
+// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct'
+// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'
+// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl<T> GenericStruct<T>'
+// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)'
+// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl<T> Foo for GenericStruct<T>'
+// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs.
+// @!has - '//h3' 'impl Bar for GenericStruct<u32> {}'
+// Same goes for the `Deref` impl.
+// @!has - '//h2' 'Methods from Deref<Target = u32>'
+// @count - '//nav[@class="sidebar"]//a' 'on_alias' 1
+// @count - '//nav[@class="sidebar"]//a' 'on_gen' 1
+// @count - '//nav[@class="sidebar"]//a' 'Foo' 1
+// @!has - '//nav[@class="sidebar"]//a' 'Bar'
+// @!has - '//nav[@class="sidebar"]//a' 'on_u32'
+pub type TypedefStruct = GenericStruct<u8>;
+
+impl TypedefStruct {
+    pub fn on_alias() {}
+}
+
+impl std::ops::Deref for GenericStruct<u32> {
+    type Target = u32;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+pub struct Wrap<T>(GenericStruct<T>);
+
+// @has 'foo/type.Alias.html'
+// @has - '//h2' 'Methods from Deref<Target = u32>'
+// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl<T> Deref for Wrap<T>'
+pub type Alias = Wrap<u32>;
+
+impl<T> std::ops::Deref for Wrap<T> {
+    type Target = GenericStruct<T>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
diff --git a/tests/rustdoc/issue-88600.rs b/tests/rustdoc/issue-88600.rs
index db0d102b741..f89af472f6e 100644
--- a/tests/rustdoc/issue-88600.rs
+++ b/tests/rustdoc/issue-88600.rs
@@ -8,10 +8,10 @@ pub struct S;
 
 // @has issue_88600/enum.FooEnum.html
 pub enum FooEnum {
-    // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(_)'
+    // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(/* private fields */)'
     // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0
     HiddenTupleItem(#[doc(hidden)] H),
-    // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(_, _)'
+    // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(/* private fields */)'
     // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0
     // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0
     MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H),
diff --git a/tests/rustdoc/private-fields-tuple-struct.rs b/tests/rustdoc/private-fields-tuple-struct.rs
new file mode 100644
index 00000000000..c6989dd8cdf
--- /dev/null
+++ b/tests/rustdoc/private-fields-tuple-struct.rs
@@ -0,0 +1,15 @@
+// This test checks the diplay of "/* private fields */" sentence in tuple structs.
+#![crate_name = "foo"]
+
+// @has 'foo/struct.A.html' '//*[@class="rust item-decl"]/code' 'pub struct A(pub u8, _);'
+pub struct A(pub u8, u8);
+// @has 'foo/struct.B.html' '//*[@class="rust item-decl"]/code' 'pub struct B(_, pub u8);'
+pub struct B(u8, pub u8);
+// @has 'foo/struct.C.html' '//*[@class="rust item-decl"]/code' 'pub struct C(_, pub u8, _);'
+pub struct C(u8, pub u8, u8);
+// @has 'foo/struct.D.html' '//*[@class="rust item-decl"]/code' 'pub struct D(pub u8, _, pub u8);'
+pub struct D(pub u8, u8, pub u8);
+// @has 'foo/struct.E.html' '//*[@class="rust item-decl"]/code' 'pub struct E(/* private fields */);'
+pub struct E(u8);
+// @has 'foo/struct.F.html' '//*[@class="rust item-decl"]/code' 'pub struct F(/* private fields */);'
+pub struct F(u8, u8);
diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs
new file mode 100644
index 00000000000..ff84352d716
--- /dev/null
+++ b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs
@@ -0,0 +1,34 @@
+#![crate_name = "inner_types_lazy"]
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// @has 'inner_types_lazy/struct.Pair.html'
+pub struct Pair<A, B> {
+    pub first: A,
+    pub second: B,
+}
+
+// @has 'inner_types_lazy/type.ReversedTypesPair.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @count - '//span[@class="where fmt-newline"]' 0
+pub type ReversedTypesPair<Q, R> = Pair<R, Q>;
+
+// @has 'inner_types_lazy/type.ReadWrite.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @count - '//span[@class="where fmt-newline"]' 2
+pub type ReadWrite<R, W> = Pair<R, W>
+where
+    R: std::io::Read,
+    W: std::io::Write;
+
+// @has 'inner_types_lazy/type.VecPair.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @count - '//span[@class="where fmt-newline"]' 0
+pub type VecPair<U, V> = Pair<Vec<U>, Vec<V>>;
diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs
new file mode 100644
index 00000000000..b734714fd64
--- /dev/null
+++ b/tests/rustdoc/typedef-inner-variants.rs
@@ -0,0 +1,119 @@
+// This test checks different combinations of structs, enums, and unions
+// for the "Show Aliased Type" feature on type definition.
+
+#![crate_name = "inner_variants"]
+
+// aux-build:cross_crate_generic_typedef.rs
+extern crate cross_crate_generic_typedef;
+
+pub struct Adt;
+pub struct Ty;
+pub struct TyCtxt;
+
+pub trait Interner {
+    type Adt;
+    type Ty;
+}
+
+impl Interner for TyCtxt {
+    type Adt = Adt;
+    type Ty = Ty;
+}
+
+// @has 'inner_variants/type.AliasTy.html'
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 0
+pub type AliasTy = Ty;
+
+// @has 'inner_variants/enum.IrTyKind.html'
+pub enum IrTyKind<A, I: Interner> {
+    /// Doc comment for AdtKind
+    AdtKind(I::Adt),
+    /// and another one for TyKind
+    TyKind(I::Adt, <I as Interner>::Ty),
+    // no comment
+    StructKind { a: A, },
+    #[doc(hidden)]
+    Unspecified,
+}
+
+// @has 'inner_variants/type.NearlyTyKind.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 1
+// @count - '//*[@id="fields"]' 0
+pub type NearlyTyKind<A> = IrTyKind<A, TyCtxt>;
+
+// @has 'inner_variants/type.TyKind.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 1
+// @count - '//*[@id="fields"]' 0
+// @count - '//*[@class="variant"]' 3
+// @matches - '//pre[@class="rust item-decl"]//code' "enum TyKind"
+// @has - '//pre[@class="rust item-decl"]//code/a[1]' "Adt"
+// @has - '//pre[@class="rust item-decl"]//code/a[2]' "Adt"
+// @has - '//pre[@class="rust item-decl"]//code/a[3]' "Ty"
+// @has - '//pre[@class="rust item-decl"]//code/a[4]' "i64"
+pub type TyKind = IrTyKind<i64, TyCtxt>;
+
+// @has 'inner_variants/union.OneOr.html'
+pub union OneOr<A: Copy> {
+    pub one: i64,
+    pub or: A,
+}
+
+// @has 'inner_variants/type.OneOrF64.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @count - '//*[@class="structfield small-section-header"]' 2
+// @matches - '//pre[@class="rust item-decl"]//code' "union OneOrF64"
+pub type OneOrF64 = OneOr<f64>;
+
+// @has 'inner_variants/struct.One.html'
+pub struct One<T> {
+    pub val: T,
+    #[doc(hidden)]
+    pub __hidden: T,
+    __private: T,
+}
+
+// @has 'inner_variants/type.OneU64.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @count - '//*[@class="structfield small-section-header"]' 1
+// @matches - '//pre[@class="rust item-decl"]//code' "struct OneU64"
+// @matches - '//pre[@class="rust item-decl"]//code' "pub val"
+pub type OneU64 = One<u64>;
+
+// @has 'inner_variants/struct.OnceA.html'
+pub struct OnceA<'a, A> {
+    pub a: &'a A,
+}
+
+// @has 'inner_variants/type.Once.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @matches - '//pre[@class="rust item-decl"]//code' "struct Once<'a>"
+// @matches - '//pre[@class="rust item-decl"]//code' "&'a"
+pub type Once<'a> = OnceA<'a, i64>;
+
+// @has 'inner_variants/struct.HighlyGenericStruct.html'
+pub struct HighlyGenericStruct<A, B, C, D> {
+    pub z: (A, B, C, D)
+}
+
+// @has 'inner_variants/type.HighlyGenericAABB.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+// @matches - '//pre[@class="rust item-decl"]//code' "struct HighlyGenericAABB<A, B>"
+// @matches - '//pre[@class="rust item-decl"]//code' "pub z"
+pub type HighlyGenericAABB<A, B> = HighlyGenericStruct<A, A, B, B>;
+
+// @has 'inner_variants/type.InlineU64.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 0
+// @count - '//*[@id="fields"]' 1
+pub use cross_crate_generic_typedef::InlineU64;
diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html
index 3e72ba2b74f..46708b9e4e9 100644
--- a/tests/rustdoc/where.SWhere_Simd_item-decl.html
+++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html
@@ -1,3 +1,3 @@
-<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(_)
+<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(/* private fields */)
 <span class="where">where
     T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html
index a7700055c9a..0c0b2d1ceca 100644
--- a/tests/rustdoc/where.alpha_trait_decl.html
+++ b/tests/rustdoc/where.alpha_trait_decl.html
@@ -1,3 +1,3 @@
-<code>pub struct Alpha&lt;A&gt;(_)
+<code>pub struct Alpha&lt;A&gt;(/* private fields */)
 <span class="where">where
     A: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code>
\ No newline at end of file
diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs
index 2aa9c8b5461..aea02c14039 100644
--- a/tests/rustdoc/where.rs
+++ b/tests/rustdoc/where.rs
@@ -4,7 +4,7 @@ use std::io::Lines;
 
 pub trait MyTrait { fn dummy(&self) { } }
 
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(/* private fields */) where A: MyTrait"
 // @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code'
 pub struct Alpha<A>(A) where A: MyTrait;
 // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
index b060e3a3e38..0e661795999 100644
--- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
+++ b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr
@@ -1,9 +1,12 @@
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
 
 warning: item is named 'lintme'
@@ -22,8 +25,9 @@ LL | #![plugin(lint_tool_test)]
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
    |
+   = help: change it to clippy::test_lint
    = note: requested on the command line with `-A test_lint`
 
 warning: 5 warnings emitted
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 182f97373ea..a11720c4b55 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -8,6 +8,7 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
+#![feature(control_flow_enum)]
 
 extern crate rustc_hir;
 extern crate rustc_middle;
@@ -15,7 +16,10 @@ extern crate rustc_smir;
 
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::TyCtxt;
-use rustc_smir::{rustc_internal, stable_mir};
+use rustc_smir::{
+    rustc_internal,
+    stable_mir::{self, fold::Foldable},
+};
 use std::assert_matches::assert_matches;
 use std::io::Write;
 use std::ops::ControlFlow;
@@ -110,6 +114,50 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> {
         other => panic!("{other:?}"),
     }
 
+    let monomorphic = get_item(tcx, &items, (DefKind::Fn, "monomorphic")).unwrap();
+    for block in monomorphic.body().blocks {
+        match &block.terminator {
+            stable_mir::mir::Terminator::Call { func, .. } => match func {
+                stable_mir::mir::Operand::Constant(c) => match &c.literal.literal {
+                    stable_mir::ty::ConstantKind::Allocated(alloc) => {
+                        assert!(alloc.bytes.is_empty());
+                        match c.literal.ty.kind() {
+                            stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::FnDef(
+                                def,
+                                mut args,
+                            )) => {
+                                let func = def.body();
+                                match func.locals[1]
+                                    .fold(&mut args)
+                                    .continue_value()
+                                    .unwrap()
+                                    .kind()
+                                {
+                                    stable_mir::ty::TyKind::RigidTy(
+                                        stable_mir::ty::RigidTy::Uint(_),
+                                    ) => {}
+                                    stable_mir::ty::TyKind::RigidTy(
+                                        stable_mir::ty::RigidTy::Tuple(_),
+                                    ) => {}
+                                    other => panic!("{other:?}"),
+                                }
+                            }
+                            other => panic!("{other:?}"),
+                        }
+                    }
+                    other => panic!("{other:?}"),
+                },
+                other => panic!("{other:?}"),
+            },
+            stable_mir::mir::Terminator::Return => {}
+            other => panic!("{other:?}"),
+        }
+    }
+
+    let foo_const = get_item(tcx, &items, (DefKind::Const, "FOO")).unwrap();
+    // Ensure we don't panic trying to get the body of a constant.
+    foo_const.body();
+
     ControlFlow::Continue(())
 }
 
@@ -147,6 +195,18 @@ fn generate_input(path: &str) -> std::io::Result<()> {
     write!(
         file,
         r#"
+    pub const FOO: u32 = 1 + 2;
+
+    fn generic<T, const U: usize>(t: T) -> [(); U] {{
+        _ = t;
+        [(); U]
+    }}
+
+    pub fn monomorphic() {{
+        generic::<(), 5>(());
+        generic::<u32, 0>(45);
+    }}
+
     mod foo {{
         pub fn bar(i: i32) -> i64 {{
             i as i64
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
new file mode 100644
index 00000000000..bfe0a5cf81d
--- /dev/null
+++ b/tests/ui/abi/compatibility.rs
@@ -0,0 +1,144 @@
+// check-pass
+#![feature(rustc_attrs, transparent_unions)]
+#![allow(unused, improper_ctypes_definitions)]
+use std::marker::PhantomData;
+use std::mem::ManuallyDrop;
+use std::num::NonZeroI32;
+use std::ptr::NonNull;
+
+macro_rules! assert_abi_compatible {
+    ($name:ident, $t1:ty, $t2:ty) => {
+        mod $name {
+            use super::*;
+            // Test argument and return value, `Rust` and `C` ABIs.
+            #[rustc_abi(assert_eq)]
+            type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2);
+            #[rustc_abi(assert_eq)]
+            type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2);
+        }
+    };
+}
+
+#[derive(Copy, Clone)]
+struct Zst;
+
+#[repr(C)]
+struct ReprC1<T>(T);
+#[repr(C)]
+struct ReprC2Int<T>(i32, T);
+#[repr(C)]
+struct ReprC2Float<T>(f32, T);
+#[repr(C)]
+struct ReprC4<T>(T, Vec<i32>, Zst, T);
+#[repr(C)]
+struct ReprC4Mixed<T>(T, f32, i32, T);
+#[repr(C)]
+enum ReprCEnum<T> {
+    Variant1,
+    Variant2(T),
+}
+#[repr(C)]
+union ReprCUnion<T> {
+    nothing: (),
+    something: ManuallyDrop<T>,
+}
+
+macro_rules! test_abi_compatible {
+    ($name:ident, $t1:ty, $t2:ty) => {
+        mod $name {
+            use super::*;
+            assert_abi_compatible!(plain, $t1, $t2);
+            // We also do some tests with differences in fields of `repr(C)` types.
+            assert_abi_compatible!(repr_c_1, ReprC1<$t1>, ReprC1<$t2>);
+            assert_abi_compatible!(repr_c_2_int, ReprC2Int<$t1>, ReprC2Int<$t2>);
+            assert_abi_compatible!(repr_c_2_float, ReprC2Float<$t1>, ReprC2Float<$t2>);
+            assert_abi_compatible!(repr_c_4, ReprC4<$t1>, ReprC4<$t2>);
+            assert_abi_compatible!(repr_c_4mixed, ReprC4Mixed<$t1>, ReprC4Mixed<$t2>);
+            assert_abi_compatible!(repr_c_enum, ReprCEnum<$t1>, ReprCEnum<$t2>);
+            assert_abi_compatible!(repr_c_union, ReprCUnion<$t1>, ReprCUnion<$t2>);
+        }
+    };
+}
+
+// Compatibility of pointers is probably de-facto guaranteed,
+// but that does not seem to be documented.
+test_abi_compatible!(ptr_mut, *const i32, *mut i32);
+test_abi_compatible!(ptr_pointee, *const i32, *const Vec<i32>);
+test_abi_compatible!(ref_mut, &i32, &mut i32);
+test_abi_compatible!(ref_ptr, &i32, *const i32);
+test_abi_compatible!(box_ptr, Box<i32>, *const i32);
+test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
+test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32);
+
+// Some further guarantees we will likely (have to) make.
+test_abi_compatible!(zst_unit, Zst, ());
+test_abi_compatible!(zst_array, Zst, [u8; 0]);
+test_abi_compatible!(nonzero_int, NonZeroI32, i32);
+
+// `repr(transparent)` compatibility.
+#[repr(transparent)]
+struct Wrapper1<T>(T);
+#[repr(transparent)]
+struct Wrapper2<T>((), Zst, T);
+#[repr(transparent)]
+struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
+#[repr(transparent)]
+union WrapperUnion<T> {
+    nothing: (),
+    something: ManuallyDrop<T>,
+}
+
+macro_rules! test_transparent {
+    ($name:ident, $t:ty) => {
+        mod $name {
+            use super::*;
+            test_abi_compatible!(wrap1, $t, Wrapper1<$t>);
+            test_abi_compatible!(wrap2, $t, Wrapper2<$t>);
+            test_abi_compatible!(wrap3, $t, Wrapper3<$t>);
+            test_abi_compatible!(wrap4, $t, WrapperUnion<$t>);
+        }
+    };
+}
+
+test_transparent!(simple, i32);
+test_transparent!(reference, &'static i32);
+test_transparent!(zst, Zst);
+test_transparent!(unit, ());
+test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment
+test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit
+test_transparent!(triple_f32, (f32, f32, f32)); // homogeneous case
+test_transparent!(triple_f64, (f64, f64, f64));
+test_transparent!(tuple, (i32, f32, i64, f64));
+test_transparent!(empty_array, [u32; 0]);
+test_transparent!(empty_1zst_array, [u8; 0]);
+test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
+test_transparent!(large_array, [i32; 16]);
+test_transparent!(enum_, Option<i32>);
+test_transparent!(enum_niched, Option<&'static i32>);
+
+// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
+macro_rules! test_nonnull {
+    ($name:ident, $t:ty) => {
+        mod $name {
+            use super::*;
+            test_abi_compatible!(option, Option<$t>, $t);
+            test_abi_compatible!(result_err_unit, Result<$t, ()>, $t);
+            test_abi_compatible!(result_ok_unit, Result<(), $t>, $t);
+            test_abi_compatible!(result_err_zst, Result<$t, Zst>, $t);
+            test_abi_compatible!(result_ok_zst, Result<Zst, $t>, $t);
+            test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t);
+            test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t);
+        }
+    }
+}
+
+test_nonnull!(ref_, &i32);
+test_nonnull!(mut_, &mut i32);
+test_nonnull!(ref_unsized, &[i32]);
+test_nonnull!(mut_unsized, &mut [i32]);
+test_nonnull!(fn_, fn());
+test_nonnull!(nonnull, NonNull<i32>);
+test_nonnull!(nonnull_unsized, NonNull<dyn std::fmt::Debug>);
+test_nonnull!(non_zero, NonZeroI32);
+
+fn main() {}
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index 13464be275e..ac37d7b6bff 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -4,20 +4,51 @@
 // normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
 // This pattern is prepared for when we account for alignment in the niche.
 // normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL"
+// normalize-stderr-test "Leaf\(0x0*20\)" -> "Leaf(0x0...20)"
 // Some attributes are only computed for release builds:
 // compile-flags: -O
 #![feature(rustc_attrs)]
 #![crate_type = "lib"]
 
+struct S(u16);
+
 #[rustc_abi(debug)]
 fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi
 
+#[rustc_abi(debug)]
+type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi
 
 #[rustc_abi(debug)]
 fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi
 
-struct S(u16);
+#[rustc_abi(debug)]
+const C: () = (); //~ ERROR: can only be applied to
+
+impl S {
+    #[rustc_abi(debug)]
+    const C: () = (); //~ ERROR: can only be applied to
+}
+
 impl S {
     #[rustc_abi(debug)]
     fn assoc_test(&self) { } //~ ERROR: fn_abi
 }
+
+#[rustc_abi(assert_eq)]
+type TestAbiEq = (fn(bool), fn(bool));
+
+#[rustc_abi(assert_eq)]
+type TestAbiNe = (fn(u8), fn(u32)); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiNeFloat = (fn(f32), fn(u32)); //~ ERROR: ABIs are not compatible
+
+// Sign matters on some targets (such as s390x), so let's make sure we never accept this.
+#[rustc_abi(assert_eq)]
+type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 4f4ee3de4b8..f56f5c525ab 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -1,4 +1,4 @@
-error: fn_abi_of_instance(test) = FnAbi {
+error: fn_abi_of(test) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
@@ -87,16 +87,110 @@ error: fn_abi_of_instance(test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:13:1
+  --> $DIR/debug.rs:16:1
    |
 LL | fn test(_x: u8) -> bool { true }
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: fn_abi_of_instance(test_generic) = FnAbi {
+error: fn_abi_of(TestFnPtr) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: *const T,
+                       ty: bool,
+                       layout: Layout {
+                           size: Size(1 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I8,
+                                       false,
+                                   ),
+                                   valid_range: 0..=1,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: Some(
+                               Niche {
+                                   offset: Size(0 bytes),
+                                   value: Int(
+                                       I8,
+                                       false,
+                                   ),
+                                   valid_range: 0..=1,
+                               },
+                           ),
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: Zext,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: u8,
+                   layout: Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Scalar(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=255,
+                           },
+                       ),
+                       fields: Primitive,
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Direct(
+                   ArgAttributes {
+                       regular: NoUndef,
+                       arg_ext: None,
+                       pointee_size: Size(0 bytes),
+                       pointee_align: None,
+                   },
+               ),
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:19:1
+   |
+LL | type TestFnPtr = fn(bool) -> u8;
+   | ^^^^^^^^^^^^^^
+
+error: fn_abi_of(test_generic) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: *const T/#0,
                        layout: Layout {
                            size: $SOME_SIZE,
                            align: AbiAndPrefAlign {
@@ -163,16 +257,620 @@ error: fn_abi_of_instance(test_generic) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:17:1
+  --> $DIR/debug.rs:22:1
    |
 LL | fn test_generic<T>(_x: *const T) { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: fn_abi_of_instance(assoc_test) = FnAbi {
+error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+  --> $DIR/debug.rs:25:1
+   |
+LL | const C: () = ();
+   | ^^^^^^^^^^^
+
+error: ABIs are not compatible
+       left ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: u8,
+                       layout: Layout {
+                           size: Size(1 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I8,
+                                       false,
+                                   ),
+                                   valid_range: 0..=255,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+       right ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: u32,
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I32,
+                                       false,
+                                   ),
+                                   valid_range: $FULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:41:1
+   |
+LL | type TestAbiNe = (fn(u8), fn(u32));
+   | ^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+       left ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: [u8; Const { ty: usize, kind: Leaf(0x0...20) }],
+                       layout: Layout {
+                           size: Size(32 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Array {
+                               stride: Size(1 bytes),
+                               count: 32,
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(32 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       extra_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+       right ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: [u32; Const { ty: usize, kind: Leaf(0x0...20) }],
+                       layout: Layout {
+                           size: Size(128 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Array {
+                               stride: Size(4 bytes),
+                               count: 32,
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(128 bytes),
+                           pointee_align: Some(
+                               Align(4 bytes),
+                           ),
+                       },
+                       extra_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:44:1
+   |
+LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+       left ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: f32,
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: F32,
+                                   valid_range: $FULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+       right ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: u32,
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I32,
+                                       false,
+                                   ),
+                                   valid_range: $FULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:47:1
+   |
+LL | type TestAbiNeFloat = (fn(f32), fn(u32));
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+       left ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: i32,
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I32,
+                                       true,
+                                   ),
+                                   valid_range: $FULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+       right ABI = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: u32,
+                       layout: Layout {
+                           size: $SOME_SIZE,
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Scalar(
+                               Initialized {
+                                   value: Int(
+                                       I32,
+                                       false,
+                                   ),
+                                   valid_range: $FULL,
+                               },
+                           ),
+                           fields: Primitive,
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Direct(
+                       ArgAttributes {
+                           regular: NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: None,
+                       },
+                   ),
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: Rust,
+           can_unwind: $SOME_BOOL,
+       }
+  --> $DIR/debug.rs:51:1
+   |
+LL | type TestAbiNeSign = (fn(i32), fn(u32));
+   | ^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/debug.rs:54:46
+   |
+LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
+   |                                              ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+  --> $DIR/debug.rs:29:5
+   |
+LL |     const C: () = ();
+   |     ^^^^^^^^^^^
+
+error: fn_abi_of(assoc_test) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: &S,
+                       ty: &ReErased Adt(S, []),
                        layout: Layout {
                            size: $SOME_SIZE,
                            align: AbiAndPrefAlign {
@@ -251,10 +949,11 @@ error: fn_abi_of_instance(assoc_test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:22:5
+  --> $DIR/debug.rs:34:5
    |
 LL |     fn assoc_test(&self) { }
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 11 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-consts/associated-const-array-len.stderr b/tests/ui/associated-consts/associated-const-array-len.stderr
index 0e0dec35b53..e3db45810fd 100644
--- a/tests/ui/associated-consts/associated-const-array-len.stderr
+++ b/tests/ui/associated-consts/associated-const-array-len.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied
    |
 LL | const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
    |                 ^^^ the trait `Foo` is not implemented for `i32`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-const-array-len.rs:1:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index e9fe3a5e514..927422fa8dc 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -51,6 +51,11 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
 LL |     foo::<Demo>()();
    |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-105330.rs:1:1
+   |
+LL | pub trait TraitWAssocConst {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:11
    |
@@ -87,6 +92,11 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
 LL |     foo::<Demo>();
    |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-105330.rs:1:1
+   |
+LL | pub trait TraitWAssocConst {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/issue-105330.rs:11:11
    |
diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
index c2da4f57696..edce1045e24 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
@@ -13,12 +13,12 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo::<T>());
    |             ^^^^^^^^^^ future returned by `foo` is not `Send`
    |
-   = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>>`
+   = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }`
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/basic.rs:13:5
    |
 LL |     T::method().await?;
-   |     ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>>`, which is not `Send`
+   |     ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }`, which is not `Send`
 note: required by a bound in `is_send`
   --> $DIR/basic.rs:17:20
    |
diff --git a/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr b/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
index 8c3463a2832..fbc4ccd4cf4 100644
--- a/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
+++ b/tests/ui/associated-types/associated-types-ICE-when-projecting-out-of-err.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Add<A>` is not satisfied
    |
 LL |     r = r + a;
    |           ^ the trait `Add<A>` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-types-ICE-when-projecting-out-of-err.rs:15:1
+   |
+LL | trait Add<RHS=Self> {
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index bd3ee2abd2c..b3f2e16ba0d 100644
--- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(T, U): Get` is not satisfied
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
    |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-types-no-suitable-supertrait.rs:12:1
+   |
+LL | trait Get {
+   | ^^^^^^^^^
 
 error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:17:40
diff --git a/tests/ui/associated-types/defaults-suitability.stderr b/tests/ui/associated-types/defaults-suitability.stderr
index 4b2094691f8..0a8ad0f89e2 100644
--- a/tests/ui/associated-types/defaults-suitability.stderr
+++ b/tests/ui/associated-types/defaults-suitability.stderr
@@ -58,6 +58,11 @@ error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
 LL |     type Assoc: Foo<Self> = ();
    |                             ^^ the trait `Foo<Self>` is not implemented for `()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/defaults-suitability.rs:27:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
 note: required by a bound in `Bar::Assoc`
   --> $DIR/defaults-suitability.rs:34:17
    |
diff --git a/tests/ui/associated-types/issue-23595-2.stderr b/tests/ui/associated-types/issue-23595-2.stderr
index dded673f6ee..73effa9f955 100644
--- a/tests/ui/associated-types/issue-23595-2.stderr
+++ b/tests/ui/associated-types/issue-23595-2.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `anything_here_kills_it` not found for `Self`
   --> $DIR/issue-23595-2.rs:6:22
    |
 LL |     type B = C<Self::anything_here_kills_it>;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: `Self` has the following associated type: `B`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr
index a84b599b52b..266e22d4726 100644
--- a/tests/ui/associated-types/issue-59324.stderr
+++ b/tests/ui/associated-types/issue-59324.stderr
@@ -48,6 +48,12 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
    |
 LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-59324.rs:3:1
+   |
+LL | pub trait Foo: NotFoo {
+   | ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
   --> $DIR/issue-59324.rs:19:10
diff --git a/tests/ui/associated-types/issue-64855.stderr b/tests/ui/associated-types/issue-64855.stderr
index 6ad795c1117..f1016f0e3a1 100644
--- a/tests/ui/associated-types/issue-64855.stderr
+++ b/tests/ui/associated-types/issue-64855.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied
    |
 LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
    |                   ^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<T>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-64855.rs:1:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs
new file mode 100644
index 00000000000..77c9876ffa5
--- /dev/null
+++ b/tests/ui/associated-types/issue-85103-layout-debug.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ the trait bound `[E]: ToOwned` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.stderr b/tests/ui/associated-types/issue-85103-layout-debug.stderr
new file mode 100644
index 00000000000..0bdea10ba47
--- /dev/null
+++ b/tests/ui/associated-types/issue-85103-layout-debug.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `[E]: ToOwned` is not satisfied
+  --> $DIR/issue-85103-layout-debug.rs:6:21
+   |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+   |                     ^^^^^^^^^^^^ the trait `ToOwned` is not implemented for `[E]`
+   |
+note: required by a bound in `Cow`
+  --> $SRC_DIR/alloc/src/borrow.rs:LL:COL
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | type Edges<'a, E> where [E]: ToOwned = Cow<'a, [E]>;
+   |                   ++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/issue-85103.rs b/tests/ui/associated-types/issue-85103.rs
deleted file mode 100644
index 9c6a419e9f7..00000000000
--- a/tests/ui/associated-types/issue-85103.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(rustc_attrs)]
-
-use std::borrow::Cow;
-
-#[rustc_layout(debug)]
-type Edges<'a, E> = Cow<'a, [E]>;
-//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
-
-fn main() {}
diff --git a/tests/ui/associated-types/issue-85103.stderr b/tests/ui/associated-types/issue-85103.stderr
deleted file mode 100644
index 17f7148074c..00000000000
--- a/tests/ui/associated-types/issue-85103.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
-  --> $DIR/issue-85103.rs:6:1
-   |
-LL | type Edges<'a, E> = Cow<'a, [E]>;
-   | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
index 3b4689e08cc..056d9201b4a 100644
--- a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
+++ b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Foo::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:4:17
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Baz::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:13:18
    |
@@ -31,6 +41,11 @@ error[E0277]: the trait bound `bool: Bar` is not satisfied
 LL |     type Assoc = bool;
    |                  ^^^^ the trait `Bar` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `Bat::Assoc`
   --> $DIR/point-at-type-on-obligation-failure-2.rs:24:27
    |
diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr
index 5d29325c827..c855e902ba9 100644
--- a/tests/ui/async-await/async-is-unwindsafe.stderr
+++ b/tests/ui/async-await/async-is-unwindsafe.stderr
@@ -15,7 +15,7 @@ LL | |     });
    |       within this `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`
    |
    = help: within `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`
-   = note: `UnwindSafe` is implemented for `&std::task::Context<'_>`, but not for `&mut std::task::Context<'_>`
+   = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
 note: future does not implement `UnwindSafe` as this value is used across an await
   --> $DIR/async-is-unwindsafe.rs:25:18
    |
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
index 81e1e59a362..3505690f1ec 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
@@ -2,14 +2,14 @@
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
 use std::future::Future;
 use std::pin::Pin;
 use std::task::Poll;
 
-trait MyTrait {
+pub trait MyTrait {
     async fn foo(&self) -> i32;
 }
 
@@ -27,8 +27,7 @@ impl Future for MyFuture {
 }
 
 impl MyTrait for i32 {
-    // FIXME: this should eventually require `#[refine]` to compile, because it also provides
-    // `Clone`.
+    #[expect(refining_impl_trait)]
     fn foo(&self) -> impl Future<Output = i32> + Clone {
         MyFuture(*self)
     }
diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs
index fb92ec78674..0a5023176fe 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared.rs
@@ -12,7 +12,7 @@ trait MyTrait {
 }
 
 impl MyTrait for i32 {
-    fn foo(&self) -> impl Future<Output = i32> + '_ {
+    fn foo(&self) -> impl Future<Output = i32> {
         async { *self }
     }
 }
diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr
new file mode 100644
index 00000000000..3b63ec45804
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr
@@ -0,0 +1,27 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12
+   |
+LL | #![feature(return_type_notation)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely
+  --> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11
+   |
+LL |     build(Bar);
+   |     ----- ^^^ `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> Send` is not implemented for `impl Future<Output = ()> { <_ as Foo>::bar() }`
+note: required by a bound in `build`
+  --> $DIR/normalizing-self-auto-trait-issue-109924.rs:20:39
+   |
+LL | fn build<T>(_: T) where T: Foo<bar(): Send> {}
+   |                                       ^^^^ required by this bound in `build`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr
new file mode 100644
index 00000000000..6fab7178767
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12
+   |
+LL | #![feature(return_type_notation)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs
new file mode 100644
index 00000000000..b2cd9707db9
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs
@@ -0,0 +1,24 @@
+// revisions: current next
+//[current] known-bug: #109924
+//[next] check-pass
+//[next] compile-flags: -Ztrait-solver=next
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_type_notation)]
+//[next]~^ WARN the feature `return_type_notation` is incomplete
+
+trait Foo {
+    async fn bar(&self);
+}
+
+struct Bar;
+impl Foo for Bar {
+    async fn bar(&self) {}
+}
+
+fn build<T>(_: T) where T: Foo<bar(): Send> {}
+
+fn main() {
+    build(Bar);
+}
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
new file mode 100644
index 00000000000..4a6c2f9ed06
--- /dev/null
+++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
@@ -0,0 +1,16 @@
+#![allow(dead_code)]
+
+fn bar<'a>(_: std::fmt::Arguments<'a>) {}
+fn main() {
+    let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
+    //~^ ERROR temporary value dropped while borrowed
+
+    bar(x);
+
+    let foo = format_args!("{}", "hi");
+    //~^ ERROR temporary value dropped while borrowed
+    bar(foo);
+
+    let foo = format_args!("hi"); // no placeholder in arguments, so no error
+    bar(foo);
+}
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
new file mode 100644
index 00000000000..8221505b100
--- /dev/null
+++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
@@ -0,0 +1,33 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13
+   |
+LL |     let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
+   |             |
+   |             creates a temporary value which is freed while still in use
+...
+LL |     bar(x);
+   |         - borrow later used here
+   |
+   = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
+   = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
+   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15
+   |
+LL |     let foo = format_args!("{}", "hi");
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
+   |               |
+   |               creates a temporary value which is freed while still in use
+LL |
+LL |     bar(foo);
+   |         --- borrow later used here
+   |
+   = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
+   = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
+   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
new file mode 100644
index 00000000000..4653fe7375d
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+pub trait Layer {
+    fn process(&mut self) -> u32;
+}
+
+pub struct State {
+    layers: Vec<Box<dyn Layer>>,
+}
+
+impl State {
+    pub fn process(&mut self) -> u32 {
+        self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
+        //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
new file mode 100644
index 00000000000..e0f6ab1321f
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+pub trait Layer {
+    fn process(&mut self) -> u32;
+}
+
+pub struct State {
+    layers: Vec<Box<dyn Layer>>,
+}
+
+impl State {
+    pub fn process(&mut self) -> u32 {
+        self.layers.iter().fold(0, |result, mut layer| result + layer.process())
+        //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
new file mode 100644
index 00000000000..7e0fc2cf298
--- /dev/null
+++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
@@ -0,0 +1,16 @@
+error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-115259-suggest-iter-mut.rs:15:65
+   |
+LL |         self.layers.iter().fold(0, |result, mut layer| result + layer.process())
+   |                                             ---------           ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                             |
+   |                                             consider changing this binding's type to be: `&mut Box<dyn Layer>`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |         self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
+   |                     ~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
new file mode 100644
index 00000000000..f02374d8e11
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+use std::path::PathBuf;
+
+#[derive(Clone)]
+struct Container {
+    things: Vec<PathBuf>,
+}
+
+impl Container {
+    fn things(&mut self) -> &[PathBuf] {
+        &self.things
+    }
+}
+
+// contains containers
+struct ContainerContainer {
+    contained: Vec<Container>,
+}
+
+impl ContainerContainer {
+    fn contained(&self) -> &[Container] {
+        &self.contained
+    }
+
+    fn all_the_things(&mut self) -> &[PathBuf] {
+        let mut vec = self.contained.clone();
+        let _a =
+            vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+        //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
new file mode 100644
index 00000000000..2d0b837a946
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+use std::path::PathBuf;
+
+#[derive(Clone)]
+struct Container {
+    things: Vec<PathBuf>,
+}
+
+impl Container {
+    fn things(&mut self) -> &[PathBuf] {
+        &self.things
+    }
+}
+
+// contains containers
+struct ContainerContainer {
+    contained: Vec<Container>,
+}
+
+impl ContainerContainer {
+    fn contained(&self) -> &[Container] {
+        &self.contained
+    }
+
+    fn all_the_things(&mut self) -> &[PathBuf] {
+        let mut vec = self.contained.clone();
+        let _a =
+            vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+        //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
new file mode 100644
index 00000000000..19f194100a1
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
@@ -0,0 +1,16 @@
+error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45
+   |
+LL |             vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+   |                                  ---------  ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                  |
+   |                                  consider changing this binding's type to be: `&mut Container`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |             vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
+   |                 ~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
new file mode 100644
index 00000000000..8bf2625de6d
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct A {
+    a: i32,
+}
+
+impl A {
+    fn double(&mut self) {
+        self.a += self.a
+    }
+}
+
+fn baz() {
+    let mut v = [A { a: 4 }];
+    v.iter_mut().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn bar() {
+    let mut v = [A { a: 4 }];
+    v.iter_mut().rev().rev().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
new file mode 100644
index 00000000000..39bc30bf294
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct A {
+    a: i32,
+}
+
+impl A {
+    fn double(&mut self) {
+        self.a += self.a
+    }
+}
+
+fn baz() {
+    let mut v = [A { a: 4 }];
+    v.iter().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn bar() {
+    let mut v = [A { a: 4 }];
+    v.iter().rev().rev().for_each(|a| a.double());
+    //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
+    println!("{:?}", v);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
new file mode 100644
index 00000000000..fd58e433020
--- /dev/null
+++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
@@ -0,0 +1,29 @@
+error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut.rs:18:27
+   |
+LL |     v.iter().for_each(|a| a.double());
+   |                        -  ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                        |
+   |                        consider changing this binding's type to be: `&mut A`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |     v.iter_mut().for_each(|a| a.double());
+   |       ~~~~~~~~
+
+error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-62387-suggest-iter-mut.rs:25:39
+   |
+LL |     v.iter().rev().rev().for_each(|a| a.double());
+   |                                    -  ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                                    |
+   |                                    consider changing this binding's type to be: `&mut A`
+   |
+help: you may want to use `iter_mut` here
+   |
+LL |     v.iter_mut().rev().rev().for_each(|a| a.double());
+   |       ~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
index 2e2dac288a1..a3a37fd2775 100644
--- a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
+++ b/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
@@ -6,6 +6,11 @@ LL |     takes_t(t);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/coherence-unsafe-trait-object-impl.rs:6:1
+   |
+LL | trait Trait: Sized {
+   | ^^^^^^^^^^^^^^^^^^
 note: required by a bound in `takes_t`
   --> $DIR/coherence-unsafe-trait-object-impl.rs:10:15
    |
diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
index cb51d9b1ea5..b3a27566026 100644
--- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
+++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `[Adt; std::mem::size_of::<Self::Assoc>()]: Foo` i
    |
 LL |         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; std::mem::size_of::<Self::Assoc>()]`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-evaluate-array-len-on-err-1.rs:9:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/early/const-param-from-outer-fn.rs b/tests/ui/const-generics/early/const-param-from-outer-fn.rs
index c3b418ee3f8..ee57f3c4fc3 100644
--- a/tests/ui/const-generics/early/const-param-from-outer-fn.rs
+++ b/tests/ui/const-generics/early/const-param-from-outer-fn.rs
@@ -1,6 +1,6 @@
 fn foo<const X: u32>() {
     fn bar() -> u32 {
-        X //~ ERROR can't use generic parameters from outer function
+        X //~ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/const-generics/early/const-param-from-outer-fn.stderr b/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
index e3bf38b702e..826f2657905 100644
--- a/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
+++ b/tests/ui/const-generics/early/const-param-from-outer-fn.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/const-param-from-outer-fn.rs:3:9
    |
 LL | fn foo<const X: u32>() {
-   |              - const parameter from outer function
+   |              - const parameter from outer item
 LL |     fn bar() -> u32 {
-   |           - help: try using a local generic parameter instead: `<X>`
+   |           - help: try introducing a local generic parameter here: `<X>`
 LL |         X
-   |         ^ use of generic parameter from outer function
+   |         ^ use of generic parameter from outer item
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
index e50ac671eca..9391b1c1a17 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
@@ -6,7 +6,11 @@ LL |     writes_to_specific_path(&cap);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Delegates<U>` is implemented for `T`
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-85848.rs:4:1
+   |
+LL | trait _Contains<T> {
+   | ^^^^^^^^^^^^^^^^^^
 note: required for `&C` to implement `Contains<(), true>`
   --> $DIR/issue-85848.rs:21:12
    |
diff --git a/tests/ui/const-generics/issues/issue-86530.stderr b/tests/ui/const-generics/issues/issue-86530.stderr
index 620ed4f0fb2..d02808f7c56 100644
--- a/tests/ui/const-generics/issues/issue-86530.stderr
+++ b/tests/ui/const-generics/issues/issue-86530.stderr
@@ -6,6 +6,11 @@ LL |     z(" ");
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-86530.rs:4:1
+   |
+LL | pub trait X {
+   | ^^^^^^^^^^^
 note: required by a bound in `z`
   --> $DIR/issue-86530.rs:10:8
    |
diff --git a/tests/ui/consts/drop-maybe_uninit.rs b/tests/ui/consts/drop-maybe_uninit.rs
new file mode 100644
index 00000000000..2fdeae5f185
--- /dev/null
+++ b/tests/ui/consts/drop-maybe_uninit.rs
@@ -0,0 +1,17 @@
+// build-pass
+
+pub const fn f<T, const N: usize>(_: [std::mem::MaybeUninit<T>; N]) {}
+
+pub struct Blubb<T>(*const T);
+
+pub const fn g<T, const N: usize>(_: [Blubb<T>; N]) {}
+
+pub struct Blorb<const N: usize>([String; N]);
+
+pub const fn h(_: Blorb<0>) {}
+
+pub struct Wrap(Blorb<0>);
+
+pub const fn i(_: Wrap) {}
+
+fn main() {}
diff --git a/tests/ui/cross/cross-fn-cache-hole.stderr b/tests/ui/cross/cross-fn-cache-hole.stderr
index 7e15562b081..79d1713934b 100644
--- a/tests/ui/cross/cross-fn-cache-hole.stderr
+++ b/tests/ui/cross/cross-fn-cache-hole.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `i32: Bar<u32>` is not satisfied
 LL |     where i32: Foo<u32, A>
    |           ^^^^^^^^^^^^^^^^ the trait `Bar<u32>` is not implemented for `i32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/cross-fn-cache-hole.rs:11:1
+   |
+LL | trait Bar<X> { }
+   | ^^^^^^^^^^^^
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
diff --git a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs
index 063efc7b31a..15aebdf1bc9 100644
--- a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs
+++ b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs
@@ -2,13 +2,13 @@
 #![deny(drop_bounds)]
 // As a special exemption, `impl Drop` in the return position raises no error.
 // This allows a convenient way to return an unnamed drop guard.
-fn voldemort_type() -> impl Drop {
-  struct Voldemort;
-  impl Drop for Voldemort {
+fn unnameable_type() -> impl Drop {
+  struct Unnameable;
+  impl Drop for Unnameable {
     fn drop(&mut self) {}
   }
-  Voldemort
+  Unnameable
 }
 fn main() {
-  let _ = voldemort_type();
+  let _ = unnameable_type();
 }
diff --git a/tests/ui/dst/dst-bad-coerce1.stderr b/tests/ui/dst/dst-bad-coerce1.stderr
index 2c75518c298..455d15e935f 100644
--- a/tests/ui/dst/dst-bad-coerce1.stderr
+++ b/tests/ui/dst/dst-bad-coerce1.stderr
@@ -15,6 +15,11 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
 LL |     let f3: &Fat<dyn Bar> = f2;
    |                             ^^ the trait `Bar` is not implemented for `Foo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dst-bad-coerce1.rs:10:1
+   |
+LL | trait Bar { fn bar(&self) {} }
+   | ^^^^^^^^^
    = note: required for the cast from `&Fat<Foo>` to `&Fat<dyn Bar>`
 
 error[E0308]: mismatched types
@@ -34,6 +39,11 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
 LL |     let f3: &(dyn Bar,) = f2;
    |                           ^^ the trait `Bar` is not implemented for `Foo`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dst-bad-coerce1.rs:10:1
+   |
+LL | trait Bar { fn bar(&self) {} }
+   | ^^^^^^^^^
    = note: required for the cast from `&(Foo,)` to `&(dyn Bar,)`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr
index ae54b9ca707..e039bb6f1c8 100644
--- a/tests/ui/dyn-star/error.stderr
+++ b/tests/ui/dyn-star/error.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied
    |
 LL |     let dyn_i: dyn* Foo = i;
    |                           ^ the trait `Foo` is not implemented for `{integer}`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/error.rs:6:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0220.stderr b/tests/ui/error-codes/E0220.stderr
index 11763ce788d..e03eadacae4 100644
--- a/tests/ui/error-codes/E0220.stderr
+++ b/tests/ui/error-codes/E0220.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `F` not found for `Trait`
   --> $DIR/E0220.rs:5:22
    |
 LL | type Foo = dyn Trait<F=i32>;
-   |                      ^ associated type `F` not found
+   |                      ^ help: `Trait` has the following associated type: `Bar`
 
 error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified
   --> $DIR/E0220.rs:5:16
diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr
index 440e43dff81..0b0d2b09720 100644
--- a/tests/ui/error-codes/E0277.stderr
+++ b/tests/ui/error-codes/E0277.stderr
@@ -21,6 +21,11 @@ LL |     some_func(5i32);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/E0277.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `some_func`
   --> $DIR/E0277.rs:7:17
    |
diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr
index fa4b91cacef..928c8d11d20 100644
--- a/tests/ui/error-codes/E0401.stderr
+++ b/tests/ui/error-codes/E0401.stderr
@@ -1,26 +1,26 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:4:39
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |             -                         ^ use of generic parameter from outer function
+   |             -                         ^ use of generic parameter from outer item
    |             |
-   |             help: try using a local generic parameter instead: `T,`
+   |             help: try introducing a local generic parameter here: `T,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:9:16
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 ...
 LL |     fn baz<U,
-   |            - help: try using a local generic parameter instead: `T,`
+   |            - help: try introducing a local generic parameter here: `T,`
 ...
 LL |            (y: T) {
-   |                ^ use of generic parameter from outer function
+   |                ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
@@ -29,8 +29,8 @@ LL | impl<T> Iterator for A<T> {
 LL |         fn helper(sel: &Self) -> u8 {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer function
-   |                         use a type here instead
+   |                         use of generic parameter from outer item
+   |                         refer to the type directly here instead
 
 error[E0282]: type annotations needed
   --> $DIR/E0401.rs:11:5
diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs
index 8fadce526d9..77d28838a10 100644
--- a/tests/ui/error-codes/E0602.rs
+++ b/tests/ui/error-codes/E0602.rs
@@ -1,6 +1,8 @@
 // compile-flags:-D bogus
+// check-pass
 
 // error-pattern:E0602
 // error-pattern:requested on the command line with `-D bogus`
+// error-pattern:`#[warn(unknown_lints)]` on by default
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0602.stderr b/tests/ui/error-codes/E0602.stderr
index 2b372263345..60ecec7cdd7 100644
--- a/tests/ui/error-codes/E0602.stderr
+++ b/tests/ui/error-codes/E0602.stderr
@@ -1,11 +1,16 @@
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error: aborting due to 2 previous errors
+warning[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+warning: 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/feature-gates/print-with-path.cfg.stderr b/tests/ui/feature-gates/print-with-path.cfg.stderr
deleted file mode 100644
index a6c51baa320..00000000000
--- a/tests/ui/feature-gates/print-with-path.cfg.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: the `-Z unstable-options` flag must also be passed to enable the path print option
-
diff --git a/tests/ui/feature-gates/print-with-path.rs b/tests/ui/feature-gates/print-with-path.rs
deleted file mode 100644
index f929c14c218..00000000000
--- a/tests/ui/feature-gates/print-with-path.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// check-fail
-// revisions: cfg target-features target-cpus
-// [cfg]compile-flags: --print cfg=cfg.txt
-// [target-cpus]compile-flags: --print target-cpu=target_cpu.txt
-// [target-features]compile-flags: --print target-features=target_features.txt
-
-fn main() {}
diff --git a/tests/ui/feature-gates/print-with-path.target-cpus.stderr b/tests/ui/feature-gates/print-with-path.target-cpus.stderr
deleted file mode 100644
index a6c51baa320..00000000000
--- a/tests/ui/feature-gates/print-with-path.target-cpus.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: the `-Z unstable-options` flag must also be passed to enable the path print option
-
diff --git a/tests/ui/feature-gates/print-with-path.target-features.stderr b/tests/ui/feature-gates/print-with-path.target-features.stderr
deleted file mode 100644
index a6c51baa320..00000000000
--- a/tests/ui/feature-gates/print-with-path.target-features.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: the `-Z unstable-options` flag must also be passed to enable the path print option
-
diff --git a/tests/ui/fn/keyword-order.stderr b/tests/ui/fn/keyword-order.stderr
index d3b140c8528..97d8f91b1ee 100644
--- a/tests/ui/fn/keyword-order.stderr
+++ b/tests/ui/fn/keyword-order.stderr
@@ -11,6 +11,8 @@ error: expected item, found keyword `pub`
    |
 LL | default pub const async unsafe extern fn err() {}
    |         ^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/generic-associated-types/issue-101020.stderr b/tests/ui/generic-associated-types/issue-101020.stderr
index 5c8db617c17..91967fb8509 100644
--- a/tests/ui/generic-associated-types/issue-101020.stderr
+++ b/tests/ui/generic-associated-types/issue-101020.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satis
 LL |     (&mut EmptyIter).consume(());
    |                      ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-101020.rs:28:1
+   |
+LL | trait Foo<T> {}
+   | ^^^^^^^^^^^^
 note: required for `&'a mut ()` to implement `for<'a> FuncInput<'a, &'a mut ()>`
   --> $DIR/issue-101020.rs:27:20
    |
diff --git a/tests/ui/generics/issue-94432-garbage-ice.rs b/tests/ui/generics/issue-94432-garbage-ice.rs
index d0709e2d2a4..4ddb3a7e9f8 100644
--- a/tests/ui/generics/issue-94432-garbage-ice.rs
+++ b/tests/ui/generics/issue-94432-garbage-ice.rs
@@ -4,7 +4,7 @@
 
 fn�a<e>(){fn�p(){e}} //~ ERROR unknown start of token: \u{fffd}
 //~^ ERROR unknown start of token: \u{fffd}
-//~^^ ERROR can't use generic parameters from outer function [E0401]
+//~^^ ERROR can't use generic parameters from outer item [E0401]
 //~^^^ WARN type parameter `e` should have an upper camel case name
 
 fn main(){}
diff --git a/tests/ui/generics/issue-98432.rs b/tests/ui/generics/issue-98432.rs
index 780c50d6ffa..c31dea76c09 100644
--- a/tests/ui/generics/issue-98432.rs
+++ b/tests/ui/generics/issue-98432.rs
@@ -2,7 +2,7 @@ struct Struct<T>(T);
 
 impl<T> Struct<T> {
     const CONST: fn() = || {
-        struct _Obligation where T:; //~ ERROR can't use generic parameters from outer function
+        struct _Obligation where T:; //~ ERROR can't use generic parameters from outer item
     };
 }
 
diff --git a/tests/ui/generics/issue-98432.stderr b/tests/ui/generics/issue-98432.stderr
index c7b5c33618d..0736d94106e 100644
--- a/tests/ui/generics/issue-98432.stderr
+++ b/tests/ui/generics/issue-98432.stderr
@@ -1,13 +1,13 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-98432.rs:5:34
    |
 LL | impl<T> Struct<T> {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     const CONST: fn() = || {
 LL |         struct _Obligation where T:;
-   |                           -      ^ use of generic parameter from outer function
+   |                           -      ^ use of generic parameter from outer item
    |                           |
-   |                           help: try using a local generic parameter instead: `<T>`
+   |                           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
index edef6ccd34e..7fe803550bd 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL |     C: StackContext,
    |        ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
@@ -26,6 +31,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL | impl<C> EthernetWorker<C> {}
    |         ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
@@ -48,6 +58,11 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
 LL |     type Handler = Ctx<C::Dispatcher>;
    |                    ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89118.rs:1:1
+   |
+LL | trait BufferMut {}
+   | ^^^^^^^^^^^^^^^
 note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
   --> $DIR/issue-89118.rs:5:23
    |
diff --git a/tests/ui/impl-trait/async_scope_creep.rs b/tests/ui/impl-trait/async_scope_creep.rs
index 7a9d64d339f..9a8831a299e 100644
--- a/tests/ui/impl-trait/async_scope_creep.rs
+++ b/tests/ui/impl-trait/async_scope_creep.rs
@@ -1,6 +1,7 @@
 #![feature(type_alias_impl_trait)]
 // edition:2021
-// check-pass
+//[rpit] check-pass
+// revisions: tait rpit
 
 struct Pending {}
 
@@ -12,15 +13,23 @@ impl AsyncRead for i32 {}
 
 type PendingReader<'a> = impl AsyncRead + 'a;
 
-type OpeningReadFuture<'a> =
-    impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
+#[cfg(tait)]
+type OpeningReadFuture<'a> = impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
 
 impl Pending {
     async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
         Ok(42)
     }
 
+    #[cfg(tait)]
     fn read_fut(&mut self) -> OpeningReadFuture<'_> {
+        self.read() //[tait]~ ERROR: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+    }
+
+    #[cfg(rpit)]
+    fn read_fut(
+        &mut self,
+    ) -> impl std::future::Future<Output = Result<PendingReader<'_>, CantOpen>> {
         self.read()
     }
 }
diff --git a/tests/ui/impl-trait/async_scope_creep.tait.stderr b/tests/ui/impl-trait/async_scope_creep.tait.stderr
new file mode 100644
index 00000000000..165096a0574
--- /dev/null
+++ b/tests/ui/impl-trait/async_scope_creep.tait.stderr
@@ -0,0 +1,9 @@
+error[E0284]: type annotations needed: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+  --> $DIR/async_scope_creep.rs:26:9
+   |
+LL |         self.read()
+   |         ^^^^^^^^^^^ cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs
index cfc2193f633..6e99402113a 100644
--- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs
+++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs
@@ -1,4 +1,4 @@
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 
 use std::ops::Deref;
 
@@ -8,6 +8,7 @@ pub trait Foo {
 
 pub struct Foreign;
 impl Foo for Foreign {
+    #[expect(refining_impl_trait)]
     fn bar(self) -> &'static () {
         &()
     }
diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
index ff7ad4bf389..fbbbb8585d1 100644
--- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
+++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs
@@ -2,7 +2,7 @@
 
 #![feature(return_position_impl_trait_in_trait)]
 
-trait Iterable {
+pub trait Iterable {
     type Item<'a>
     where
         Self: 'a;
@@ -17,6 +17,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
     //~^ ERROR impl has stricter requirements than trait
 
     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
+        //~^ WARN impl trait in impl method signature does not match trait method signature
         (*self).iter()
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
index 106b8a7c804..a5fb338ea4e 100644
--- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
+++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
@@ -12,6 +12,22 @@ help: copy the `where` clause predicates from the trait
 LL |     where Self: 'b;
    |     ~~~~~~~~~~~~~~
 
-error: aborting due to previous error
+warning: impl trait in impl method signature does not match trait method signature
+  --> $DIR/bad-item-bound-within-rpitit.rs:19:28
+   |
+LL |     fn iter(&self) -> impl '_ + Iterator<Item = Self::Item<'_>>;
+   |                       ----------------------------------------- return type from trait method defined here
+...
+LL |     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
+   |                            ^^ this bound is stronger than that defined on the trait
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: `#[warn(refining_impl_trait)]` on by default
+help: replace the return type so that it matches the trait
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = <Self as Iterable>::Item<'_>> + '_ {
+   |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs
index 78cff97c616..fc290f11f9d 100644
--- a/tests/ui/impl-trait/in-trait/deep-match-works.rs
+++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs
@@ -1,15 +1,16 @@
 // check-pass
 
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
-struct Wrapper<T>(T);
+pub struct Wrapper<T>(T);
 
-trait Foo {
+pub trait Foo {
     fn bar() -> Wrapper<impl Sized>;
 }
 
 impl Foo for () {
+    #[expect(refining_impl_trait)]
     fn bar() -> Wrapper<i32> {
         Wrapper(0)
     }
diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs
index b0c93a02935..6285d7786d5 100644
--- a/tests/ui/impl-trait/in-trait/foreign.rs
+++ b/tests/ui/impl-trait/in-trait/foreign.rs
@@ -1,14 +1,25 @@
 // check-pass
 // aux-build: rpitit.rs
 
+#![feature(lint_reasons)]
+
 extern crate rpitit;
 
 use rpitit::{Foo, Foreign};
 use std::sync::Arc;
 
 // Implement an RPITIT from another crate.
-struct Local;
+pub struct Local;
 impl Foo for Local {
+    #[expect(refining_impl_trait)]
+    fn bar(self) -> Arc<String> {
+        Arc::new(String::new())
+    }
+}
+
+struct LocalIgnoreRefining;
+impl Foo for LocalIgnoreRefining {
+    #[deny(refining_impl_trait)]
     fn bar(self) -> Arc<String> {
         Arc::new(String::new())
     }
@@ -23,4 +34,5 @@ fn main() {
     let &() = Foreign.bar();
 
     let x: Arc<String> = Local.bar();
+    let x: Arc<String> = LocalIgnoreRefining.bar();
 }
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs
index 61c91e64417..ccb53031c44 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102571.rs
@@ -8,14 +8,6 @@ trait Foo {
     fn bar(self) -> impl Deref<Target = impl Display + ?Sized>;
 }
 
-struct A;
-
-impl Foo for A {
-    fn bar(self) -> &'static str {
-        "Hello, world"
-    }
-}
-
 fn foo<T: Foo>(t: T) {
     let () = t.bar();
     //~^ ERROR mismatched types
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr
index 87219941d91..594b9ae9cd6 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-102571.rs:20:9
+  --> $DIR/issue-102571.rs:12:9
    |
 LL |     let () = t.bar();
    |         ^^   ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs
index 65285e3a3cc..58ba1acaf14 100644
--- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs
+++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs
@@ -1,26 +1,28 @@
 // check-pass
 
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
 use std::fmt::Display;
 use std::ops::Deref;
 
-trait Foo {
+pub trait Foo {
     fn bar(self) -> impl Deref<Target = impl Display + ?Sized>;
 }
 
-struct A;
+pub struct A;
 
 impl Foo for A {
+    #[expect(refining_impl_trait)]
     fn bar(self) -> &'static str {
         "Hello, world"
     }
 }
 
-struct B;
+pub struct B;
 
 impl Foo for B {
+    #[expect(refining_impl_trait)]
     fn bar(self) -> Box<i32> {
         Box::new(42)
     }
diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index 9a231e59b09..d1c9fba4e99 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -8,7 +8,7 @@ trait Foo {
 }
 
 impl Foo for u32 {
-    fn baz(&self) -> u32 {
+    fn baz(&self) -> impl Debug {
         32
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/refine.rs b/tests/ui/impl-trait/in-trait/refine.rs
new file mode 100644
index 00000000000..a91f9b3e722
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/refine.rs
@@ -0,0 +1,48 @@
+#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
+#![deny(refining_impl_trait)]
+
+pub trait Foo {
+    fn bar() -> impl Sized;
+}
+
+pub struct A;
+impl Foo for A {
+    fn bar() -> impl Copy {}
+    //~^ ERROR impl method signature does not match trait method signature
+}
+
+pub struct B;
+impl Foo for B {
+    fn bar() {}
+    //~^ ERROR impl method signature does not match trait method signature
+}
+
+pub struct C;
+impl Foo for C {
+    fn bar() -> () {}
+    //~^ ERROR impl method signature does not match trait method signature
+}
+
+struct Private;
+impl Foo for Private {
+    fn bar() -> () {}
+}
+
+pub trait Arg<A> {
+    fn bar() -> impl Sized;
+}
+impl Arg<Private> for A {
+    fn bar() -> () {}
+}
+
+pub trait Late {
+    fn bar<'a>(&'a self) -> impl Sized + 'a;
+}
+
+pub struct D;
+impl Late for D {
+    fn bar(&self) -> impl Copy + '_ {}
+    //~^ ERROR impl method signature does not match trait method signature
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr
new file mode 100644
index 00000000000..29aa08e25bb
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/refine.stderr
@@ -0,0 +1,67 @@
+error: impl trait in impl method signature does not match trait method signature
+  --> $DIR/refine.rs:10:22
+   |
+LL |     fn bar() -> impl Sized;
+   |                 ---------- return type from trait method defined here
+...
+LL |     fn bar() -> impl Copy {}
+   |                      ^^^^ this bound is stronger than that defined on the trait
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+note: the lint level is defined here
+  --> $DIR/refine.rs:2:9
+   |
+LL | #![deny(refining_impl_trait)]
+   |         ^^^^^^^^^^^^^^^^^^^
+help: replace the return type so that it matches the trait
+   |
+LL |     fn bar() -> impl Sized {}
+   |                 ~~~~~~~~~~
+
+error: impl trait in impl method signature does not match trait method signature
+  --> $DIR/refine.rs:16:5
+   |
+LL |     fn bar() -> impl Sized;
+   |                 ---------- return type from trait method defined here
+...
+LL |     fn bar() {}
+   |     ^^^^^^^^
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+help: replace the return type so that it matches the trait
+   |
+LL |     fn bar() -> impl Sized {}
+   |              +++++++++++++
+
+error: impl trait in impl method signature does not match trait method signature
+  --> $DIR/refine.rs:22:17
+   |
+LL |     fn bar() -> impl Sized;
+   |                 ---------- return type from trait method defined here
+...
+LL |     fn bar() -> () {}
+   |                 ^^
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+help: replace the return type so that it matches the trait
+   |
+LL |     fn bar() -> impl Sized {}
+   |                 ~~~~~~~~~~
+
+error: impl trait in impl method signature does not match trait method signature
+  --> $DIR/refine.rs:44:27
+   |
+LL |     fn bar<'a>(&'a self) -> impl Sized + 'a;
+   |                             --------------- return type from trait method defined here
+...
+LL |     fn bar(&self) -> impl Copy + '_ {}
+   |                           ^^^^ this bound is stronger than that defined on the trait
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+help: replace the return type so that it matches the trait
+   |
+LL |     fn bar(&self) -> impl Sized + '_ {}
+   |                      ~~~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs
index d6ede1cc495..b1b46d75b8f 100644
--- a/tests/ui/impl-trait/in-trait/reveal.rs
+++ b/tests/ui/impl-trait/in-trait/reveal.rs
@@ -1,13 +1,14 @@
 // check-pass
 
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
-trait Foo {
+pub trait Foo {
     fn f() -> Box<impl Sized>;
 }
 
 impl Foo for () {
+    #[expect(refining_impl_trait)]
     fn f() -> Box<String> {
         Box::new(String::new())
     }
diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs
index 7682884f879..44a2b430344 100644
--- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs
+++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs
@@ -1,6 +1,6 @@
 // issue: 113903
 
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 
 use std::ops::Deref;
 
@@ -10,6 +10,7 @@ pub trait Tr {
 }
 
 impl Tr for () {
+    #[expect(refining_impl_trait)]
     fn w() -> &'static () {
         &()
     }
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
index 186580f5756..468cf12f1bc 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
@@ -1,5 +1,5 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/signature-mismatch.rs:77:10
+  --> $DIR/signature-mismatch.rs:79:10
    |
 LL |         &'a self,
    |         -------- this parameter and the return type are declared with different lifetimes...
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
index c84a3b8f46b..685c0f06e88 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
@@ -2,18 +2,17 @@
 // revisions: success failure
 //[success] check-pass
 
-#![feature(return_position_impl_trait_in_trait)]
-#![allow(incomplete_features)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 
 use std::future::Future;
 
-trait Captures<'a> {}
+pub trait Captures<'a> {}
 impl<T> Captures<'_> for T {}
 
-trait Captures2<'a, 'b> {}
+pub trait Captures2<'a, 'b> {}
 impl<T> Captures2<'_, '_> for T {}
 
-trait AsyncTrait {
+pub trait AsyncTrait {
     #[cfg(success)]
     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
 
@@ -45,6 +44,7 @@ impl AsyncTrait for Struct {
     // Does not capture more lifetimes that trait def'n, since trait def'n
     // implicitly captures all in-scope lifetimes.
     #[cfg(success)]
+    #[expect(refining_impl_trait)]
     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
         async move { buff.to_vec() }
     }
@@ -52,6 +52,7 @@ impl AsyncTrait for Struct {
     // Does not capture more lifetimes that trait def'n, since trait def'n
     // implicitly captures all in-scope lifetimes.
     #[cfg(success)]
+    #[expect(refining_impl_trait)]
     fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
         async move { buff.to_vec() }
     }
@@ -59,6 +60,7 @@ impl AsyncTrait for Struct {
     // Does not capture more lifetimes that trait def'n, since trait def'n
     // implicitly captures all in-scope lifetimes.
     #[cfg(success)]
+    #[expect(refining_impl_trait)]
     fn async_fn_multiple<'a, 'b>(
         &'a self,
         buff: &'b [u8],
diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
index c9ee877db8e..41fc285883a 100644
--- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
+++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs
@@ -1,10 +1,10 @@
 // check-pass
 
 #![feature(specialization)]
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
-trait Foo {
+pub trait Foo {
     fn bar(&self) -> impl Sized;
 }
 
@@ -12,6 +12,7 @@ impl<U> Foo for U
 where
     U: Copy,
 {
+    #[expect(refining_impl_trait)]
     fn bar(&self) -> U {
         *self
     }
diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs
index 4cbe682b46f..7d415ea17a4 100644
--- a/tests/ui/impl-trait/in-trait/success.rs
+++ b/tests/ui/impl-trait/in-trait/success.rs
@@ -1,29 +1,32 @@
 // check-pass
 
-#![feature(return_position_impl_trait_in_trait)]
+#![feature(return_position_impl_trait_in_trait, lint_reasons)]
 #![allow(incomplete_features)]
 
 use std::fmt::Display;
 
-trait Foo {
+pub trait Foo {
     fn bar(&self) -> impl Display;
 }
 
 impl Foo for i32 {
+    #[expect(refining_impl_trait)]
     fn bar(&self) -> i32 {
         *self
     }
 }
 
 impl Foo for &'static str {
+    #[expect(refining_impl_trait)]
     fn bar(&self) -> &'static str {
         *self
     }
 }
 
-struct Yay;
+pub struct Yay;
 
 impl Foo for Yay {
+    #[expect(refining_impl_trait)]
     fn bar(&self) -> String {
         String::from(":^)")
     }
diff --git a/tests/ui/inner-static-type-parameter.rs b/tests/ui/inner-static-type-parameter.rs
index c08ccd29d80..a1994e7529c 100644
--- a/tests/ui/inner-static-type-parameter.rs
+++ b/tests/ui/inner-static-type-parameter.rs
@@ -4,7 +4,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
 
 fn foo<T>() {
     static a: Bar<T> = Bar::What;
-//~^ ERROR can't use generic parameters from outer function
+//~^ ERROR can't use generic parameters from outer item
 }
 
 fn main() {
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr
index e4e449e4159..ff6558e494b 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/inner-static-type-parameter.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/inner-static-type-parameter.rs:6:19
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     static a: Bar<T> = Bar::What;
-   |                   ^ use of generic parameter from outer function
+   |                   ^ use of generic parameter from outer item
 
 error[E0392]: parameter `T` is never used
   --> $DIR/inner-static-type-parameter.rs:3:10
diff --git a/tests/ui/issues/issue-18611.stderr b/tests/ui/issues/issue-18611.stderr
index bd18d46223e..784b9b984e9 100644
--- a/tests/ui/issues/issue-18611.stderr
+++ b/tests/ui/issues/issue-18611.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied
    |
 LL | fn add_state(op: <isize as HasState>::State) {
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-18611.rs:5:1
+   |
+LL | trait HasState {
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-25076.stderr b/tests/ui/issues/issue-25076.stderr
index 159cc484c5d..065bf7def42 100644
--- a/tests/ui/issues/issue-25076.stderr
+++ b/tests/ui/issues/issue-25076.stderr
@@ -6,6 +6,11 @@ LL |     do_fold(bot(), ());
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-25076.rs:3:1
+   |
+LL | trait InOut<T> { type Out; }
+   | ^^^^^^^^^^^^^^
 note: required by a bound in `do_fold`
   --> $DIR/issue-25076.rs:5:18
    |
diff --git a/tests/ui/issues/issue-3214.rs b/tests/ui/issues/issue-3214.rs
index e3c07bb3f72..b2c27f5be95 100644
--- a/tests/ui/issues/issue-3214.rs
+++ b/tests/ui/issues/issue-3214.rs
@@ -1,6 +1,6 @@
 fn foo<T>() {
     struct Foo {
-        x: T, //~ ERROR can't use generic parameters from outer function
+        x: T, //~ ERROR can't use generic parameters from outer item
     }
 
     impl<T> Drop for Foo<T> {
diff --git a/tests/ui/issues/issue-3214.stderr b/tests/ui/issues/issue-3214.stderr
index 7a2d772f0a1..5b57c1baf90 100644
--- a/tests/ui/issues/issue-3214.stderr
+++ b/tests/ui/issues/issue-3214.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3214.rs:3:12
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     struct Foo {
-   |               - help: try using a local generic parameter instead: `<T>`
+   |               - help: try introducing a local generic parameter here: `<T>`
 LL |         x: T,
-   |            ^ use of generic parameter from outer function
+   |            ^ use of generic parameter from outer item
 
 error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-3214.rs:6:22
diff --git a/tests/ui/issues/issue-35570.stderr b/tests/ui/issues/issue-35570.stderr
index 2697d46bdb2..197e80ac097 100644
--- a/tests/ui/issues/issue-35570.stderr
+++ b/tests/ui/issues/issue-35570.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
    |
 LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-35570.rs:4:1
+   |
+LL | trait Trait2<'a> {
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-5997-enum.rs b/tests/ui/issues/issue-5997-enum.rs
index 3ff4e036c60..0b1857ae3df 100644
--- a/tests/ui/issues/issue-5997-enum.rs
+++ b/tests/ui/issues/issue-5997-enum.rs
@@ -1,6 +1,6 @@
 fn f<Z>() -> bool {
     enum E { V(Z) }
-    //~^ ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
     true
 }
 
diff --git a/tests/ui/issues/issue-5997-enum.stderr b/tests/ui/issues/issue-5997-enum.stderr
index 3a79215d3ae..d07258ea7a2 100644
--- a/tests/ui/issues/issue-5997-enum.stderr
+++ b/tests/ui/issues/issue-5997-enum.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-5997-enum.rs:2:16
    |
 LL | fn f<Z>() -> bool {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     enum E { V(Z) }
-   |           -    ^ use of generic parameter from outer function
+   |           -    ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<Z>`
+   |           help: try introducing a local generic parameter here: `<Z>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-5997-struct.rs b/tests/ui/issues/issue-5997-struct.rs
index 6cf510b0a9d..19d994b0dfb 100644
--- a/tests/ui/issues/issue-5997-struct.rs
+++ b/tests/ui/issues/issue-5997-struct.rs
@@ -1,5 +1,5 @@
 fn f<T>() -> bool {
-    struct S(T); //~ ERROR can't use generic parameters from outer function
+    struct S(T); //~ ERROR can't use generic parameters from outer item
 
     true
 }
diff --git a/tests/ui/issues/issue-5997-struct.stderr b/tests/ui/issues/issue-5997-struct.stderr
index d2e97f76771..83229e02c6c 100644
--- a/tests/ui/issues/issue-5997-struct.stderr
+++ b/tests/ui/issues/issue-5997-struct.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-5997-struct.rs:2:14
    |
 LL | fn f<T>() -> bool {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     struct S(T);
-   |             -^ use of generic parameter from outer function
+   |             -^ use of generic parameter from outer item
    |             |
-   |             help: try using a local generic parameter instead: `<T>`
+   |             help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-60218.stderr b/tests/ui/issues/issue-60218.stderr
index 563690c9a5d..ae3c4d12025 100644
--- a/tests/ui/issues/issue-60218.stderr
+++ b/tests/ui/issues/issue-60218.stderr
@@ -6,6 +6,11 @@ LL |     trigger_error(vec![], |x: &u32| x)
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-60218.rs:7:1
+   |
+LL | pub trait Foo {}
+   | ^^^^^^^^^^^^^
 note: required by a bound in `trigger_error`
   --> $DIR/issue-60218.rs:13:72
    |
diff --git a/tests/ui/issues/issue-66353.stderr b/tests/ui/issues/issue-66353.stderr
index 71530f58220..7ab7547b42d 100644
--- a/tests/ui/issues/issue-66353.stderr
+++ b/tests/ui/issues/issue-66353.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): _A` is not satisfied
    |
 LL |     _Func::< <() as _A>::AssocT >::func(());
    |               ^^ the trait `_A` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-66353.rs:7:1
+   |
+LL | trait _A {
+   | ^^^^^^^^
 
 error[E0277]: the trait bound `(): _Func<_>` is not satisfied
   --> $DIR/issue-66353.rs:12:41
@@ -11,6 +17,12 @@ LL |     _Func::< <() as _A>::AssocT >::func(());
    |     ----------------------------------- ^^ the trait `_Func<_>` is not implemented for `()`
    |     |
    |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-66353.rs:3:1
+   |
+LL | trait _Func<T> {
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index b74a8d3b917..65f2f3b89af 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -17,6 +17,9 @@ type Test = Result<i32, i32>; //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
 type T = impl std::fmt::Debug; //~ ERROR: layout_of
+fn f() -> T {
+    0i32
+}
 
 #[rustc_layout(debug)]
 pub union V { //~ ERROR: layout_of
@@ -63,6 +66,13 @@ union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of
 #[rustc_layout(debug)]
 type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
 
-fn f() -> T {
-    0i32
+#[rustc_layout(debug)]
+const C: () = (); //~ ERROR: can only be applied to
+
+impl S {
+    #[rustc_layout(debug)]
+    const C: () = (); //~ ERROR: can only be applied to
 }
+
+#[rustc_layout(debug)]
+type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index c20a0198ccb..5162a771b4d 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -162,7 +162,7 @@ error: layout_of(U) = Layout {
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^
 
-error: layout_of(std::result::Result<i32, i32>) = Layout {
+error: layout_of(Result<i32, i32>) = Layout {
            size: Size(8 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -344,7 +344,7 @@ error: layout_of(V) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
        }
-  --> $DIR/debug.rs:22:1
+  --> $DIR/debug.rs:25:1
    |
 LL | pub union V {
    | ^^^^^^^^^^^
@@ -368,7 +368,7 @@ error: layout_of(W) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
        }
-  --> $DIR/debug.rs:28:1
+  --> $DIR/debug.rs:31:1
    |
 LL | pub union W {
    | ^^^^^^^^^^^
@@ -392,7 +392,7 @@ error: layout_of(Y) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
        }
-  --> $DIR/debug.rs:34:1
+  --> $DIR/debug.rs:37:1
    |
 LL | pub union Y {
    | ^^^^^^^^^^^
@@ -416,7 +416,7 @@ error: layout_of(P1) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:41:1
+  --> $DIR/debug.rs:44:1
    |
 LL | union P1 { x: u32 }
    | ^^^^^^^^
@@ -440,7 +440,7 @@ error: layout_of(P2) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:45:1
+  --> $DIR/debug.rs:48:1
    |
 LL | union P2 { x: (u32, u32) }
    | ^^^^^^^^
@@ -464,7 +464,7 @@ error: layout_of(P3) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:53:1
+  --> $DIR/debug.rs:56:1
    |
 LL | union P3 { x: F32x4 }
    | ^^^^^^^^
@@ -488,7 +488,7 @@ error: layout_of(P4) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:57:1
+  --> $DIR/debug.rs:60:1
    |
 LL | union P4 { x: E }
    | ^^^^^^^^
@@ -517,12 +517,12 @@ error: layout_of(P5) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:61:1
+  --> $DIR/debug.rs:64:1
    |
 LL | union P5 { zst: [u16; 0], byte: u8 }
    | ^^^^^^^^
 
-error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
+error: layout_of(MaybeUninit<u8>) = Layout {
            size: Size(1 bytes),
            align: AbiAndPrefAlign {
                abi: Align(1 bytes),
@@ -546,10 +546,32 @@ error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
        }
-  --> $DIR/debug.rs:64:1
+  --> $DIR/debug.rs:67:1
    |
 LL | type X = std::mem::MaybeUninit<u8>;
    | ^^^^^^
 
-error: aborting due to 14 previous errors
+error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
+  --> $DIR/debug.rs:70:1
+   |
+LL | const C: () = ();
+   | ^^^^^^^^^^^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/debug.rs:78:19
+   |
+LL | type Impossible = (str, str);
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
+  --> $DIR/debug.rs:74:5
+   |
+LL |     const C: () = ();
+   |     ^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs
new file mode 100644
index 00000000000..9703d2bf294
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.rs
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+#![feature(transparent_unions)]
+use std::marker::PhantomData;
+
+// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect
+// the result of `homogeneous_aggregate`.
+
+type Tuple = (f32, f32, f32);
+
+struct Zst;
+
+#[repr(transparent)]
+struct Wrapper1<T>(T);
+#[repr(transparent)]
+struct Wrapper2<T>((), Zst, T);
+#[repr(transparent)]
+struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
+#[repr(transparent)]
+union WrapperUnion<T: Copy> {
+    nothing: (),
+    something: T,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test0 = Tuple;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test1 = Wrapper1<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test2 = Wrapper2<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test3 = Wrapper3<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test4 = WrapperUnion<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+fn main() {}
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.stderr b/tests/ui/layout/homogeneous-aggr-transparent.stderr
new file mode 100644
index 00000000000..99eb703ac82
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.stderr
@@ -0,0 +1,32 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:25:1
+   |
+LL | pub type Test0 = Tuple;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:29:1
+   |
+LL | pub type Test1 = Wrapper1<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:33:1
+   |
+LL | pub type Test2 = Wrapper2<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:37:1
+   |
+LL | pub type Test3 = Wrapper3<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:41:1
+   |
+LL | pub type Test4 = WrapperUnion<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr
index df9f1cc8d10..8161f97dde0 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.stderr
+++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr
@@ -1,4 +1,4 @@
-error: layout_of(std::result::Result<[u32; 0], bool>) = Layout {
+error: layout_of(Result<[u32; 0], bool>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -232,7 +232,7 @@ error: layout_of(MultipleAlignments) = Layout {
 LL | enum MultipleAlignments {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) = Layout {
+error: layout_of(Result<[u32; 0], Packed<NonZeroU16>>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
@@ -337,7 +337,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) =
 LL | type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZeroU16>>;
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
+error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
            size: Size(4 bytes),
            align: AbiAndPrefAlign {
                abi: Align(4 bytes),
diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr
index 5b93eff8614..6361d8ad30b 100644
--- a/tests/ui/lifetimes/issue-95023.stderr
+++ b/tests/ui/lifetimes/issue-95023.stderr
@@ -36,7 +36,7 @@ error[E0220]: associated type `B` not found for `Self`
   --> $DIR/issue-95023.rs:6:44
    |
 LL |     fn foo<const N: usize>(&self) -> Self::B<{N}>;
-   |                                            ^ associated type `B` not found
+   |                                            ^ help: `Self` has the following associated type: `Output`
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index ef1127c59ac..421ab3fcf4e 100644
--- a/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/tests/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
    |
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/lifetime-elision-return-type-trait.rs:1:1
+   |
+LL | trait Future {
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs
new file mode 100644
index 00000000000..ce8d9848e42
--- /dev/null
+++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs
@@ -0,0 +1,14 @@
+// build-fail
+// failure-status: 101
+// known-bug: #109681
+
+// This test verifies that we continue to hit the LLVM error for common linkage with non-zero
+// initializers, since it generates invalid LLVM IR.
+// Linkages are internal features marked as perma-unstable, so we don't need to fix the issue
+// for now.
+#![crate_type="lib"]
+#![feature(linkage)]
+
+#[linkage = "common"]
+#[no_mangle]
+pub static TEST: bool = true;
diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr
new file mode 100644
index 00000000000..667bb3ec130
--- /dev/null
+++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr
@@ -0,0 +1,3 @@
+'common' global must have a zero initializer!
+ptr @TEST
+LLVM ERROR: Broken module found, compilation aborted!
diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs
index f3dea87a6b6..a9e4e4a6017 100644
--- a/tests/ui/lint/cli-unknown-force-warn.rs
+++ b/tests/ui/lint/cli-unknown-force-warn.rs
@@ -1,7 +1,11 @@
 // Checks that rustc correctly errors when passed an invalid lint with
 // `--force-warn`. This is a regression test for issue #86958.
-//
+
+// check-pass
 // compile-flags: --force-warn foo-qux
+
 // error-pattern: unknown lint: `foo_qux`
+// error-pattern: requested on the command line with `--force-warn foo_qux`
+// error-pattern: `#[warn(unknown_lints)]` on by default
 
 fn main() {}
diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/cli-unknown-force-warn.stderr
index 9ce9f405aee..2ee718a8c8e 100644
--- a/tests/ui/lint/cli-unknown-force-warn.stderr
+++ b/tests/ui/lint/cli-unknown-force-warn.stderr
@@ -1,11 +1,16 @@
-error[E0602]: unknown lint: `foo_qux`
+warning[E0602]: unknown lint: `foo_qux`
    |
    = note: requested on the command line with `--force-warn foo_qux`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `foo_qux`
+warning[E0602]: unknown lint: `foo_qux`
    |
    = note: requested on the command line with `--force-warn foo_qux`
 
-error: aborting due to 2 previous errors
+warning[E0602]: unknown lint: `foo_qux`
+   |
+   = note: requested on the command line with `--force-warn foo_qux`
+
+warning: 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs
index 70dd2a71f26..ac24f61b0ac 100644
--- a/tests/ui/lint/lint-ctypes-94223.rs
+++ b/tests/ui/lint/lint-ctypes-94223.rs
@@ -24,6 +24,13 @@ enum BadUnion {
 type Foo = extern "C" fn([u8]);
 //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe
 
+pub trait FooTrait {
+    type FooType;
+}
+
+pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
+//~^ ERROR `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
+
 pub struct FfiUnsafe;
 
 #[allow(improper_ctypes_definitions)]
diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr
index 49e64ed5140..bd127cf6004 100644
--- a/tests/ui/lint/lint-ctypes-94223.stderr
+++ b/tests/ui/lint/lint-ctypes-94223.stderr
@@ -66,8 +66,17 @@ LL | type Foo = extern "C" fn([u8]);
    = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
+error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-94223.rs:31:20
+   |
+LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:34:17
+  --> $DIR/lint-ctypes-94223.rs:41:17
    |
 LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -75,13 +84,13 @@ LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:37:30
+  --> $DIR/lint-ctypes-94223.rs:44:30
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -89,13 +98,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:37:56
+  --> $DIR/lint-ctypes-94223.rs:44:56
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -103,13 +112,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:41:22
+  --> $DIR/lint-ctypes-94223.rs:48:22
    |
 LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -117,10 +126,10 @@ LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:27:1
+  --> $DIR/lint-ctypes-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
new file mode 100644
index 00000000000..ca08eb23a57
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
@@ -0,0 +1,8 @@
+#![deny(improper_ctypes_definitions)]
+
+extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+    //~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe
+    None
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
new file mode 100644
index 00000000000..f59fb3cc750
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
@@ -0,0 +1,16 @@
+error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
+   |
+LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+   |                                             ^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs
new file mode 100644
index 00000000000..8cf91cf60eb
--- /dev/null
+++ b/tests/ui/lint/lint-removed-cmdline-deny.rs
@@ -0,0 +1,13 @@
+// The raw_pointer_derived lint warns about its removal
+// cc #30346
+
+// compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive
+
+// error-pattern:lint `raw_pointer_derive` has been removed
+// error-pattern:requested on the command line with `-D raw_pointer_derive`
+// error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+
+#![warn(unused)]
+
+#[deny(warnings)]
+fn main() { let unused = (); }
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr
new file mode 100644
index 00000000000..80c85d01e53
--- /dev/null
+++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr
@@ -0,0 +1,28 @@
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+   = note: requested on the command line with `-D renamed-and-removed-lints`
+
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+error: unused variable: `unused`
+  --> $DIR/lint-removed-cmdline-deny.rs:13:17
+   |
+LL | fn main() { let unused = (); }
+   |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-removed-cmdline-deny.rs:12:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs
index 462beabb945..34373df3a9c 100644
--- a/tests/ui/lint/lint-removed-cmdline.rs
+++ b/tests/ui/lint/lint-removed-cmdline.rs
@@ -4,6 +4,7 @@
 // compile-flags:-D raw_pointer_derive
 
 // error-pattern:lint `raw_pointer_derive` has been removed
+// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
 // error-pattern:requested on the command line with `-D raw_pointer_derive`
 
 #![warn(unused)]
diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr
index 9be532ef234..ebfae34ade9 100644
--- a/tests/ui/lint/lint-removed-cmdline.stderr
+++ b/tests/ui/lint/lint-removed-cmdline.stderr
@@ -1,6 +1,7 @@
 warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
    |
    = note: requested on the command line with `-D raw_pointer_derive`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
    |
@@ -11,13 +12,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point
    = note: requested on the command line with `-D raw_pointer_derive`
 
 error: unused variable: `unused`
-  --> $DIR/lint-removed-cmdline.rs:12:17
+  --> $DIR/lint-removed-cmdline.rs:13:17
    |
 LL | fn main() { let unused = (); }
    |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
    |
 note: the lint level is defined here
-  --> $DIR/lint-removed-cmdline.rs:11:8
+  --> $DIR/lint-removed-cmdline.rs:12:8
    |
 LL | #[deny(warnings)]
    |        ^^^^^^^^
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs
new file mode 100644
index 00000000000..01629aaca80
--- /dev/null
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs
@@ -0,0 +1,10 @@
+// compile-flags:-D renamed-and-removed-lints -D bare_trait_object
+
+// error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects`
+// error-pattern:use the new name `bare_trait_objects`
+// error-pattern:requested on the command line with `-D bare_trait_object`
+// error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+// error-pattern:unused
+
+#[deny(unused)]
+fn main() { let unused = (); }
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
new file mode 100644
index 00000000000..df22ef60daf
--- /dev/null
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
@@ -0,0 +1,31 @@
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+   = note: requested on the command line with `-D renamed-and-removed-lints`
+
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = help: use the new name `bare_trait_objects`
+   = note: requested on the command line with `-D bare_trait_object`
+
+error: unused variable: `unused`
+  --> $DIR/lint-renamed-cmdline-deny.rs:10:17
+   |
+LL | fn main() { let unused = (); }
+   |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-renamed-cmdline-deny.rs:9:8
+   |
+LL | #[deny(unused)]
+   |        ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs
index c873771e308..fba7c33311d 100644
--- a/tests/ui/lint/lint-renamed-cmdline.rs
+++ b/tests/ui/lint/lint-renamed-cmdline.rs
@@ -2,6 +2,7 @@
 
 // error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects`
 // error-pattern:requested on the command line with `-D bare_trait_object`
+// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
 // error-pattern:unused
 
 #[deny(unused)]
diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr
index 8dfd61ac927..a41284003ed 100644
--- a/tests/ui/lint/lint-renamed-cmdline.stderr
+++ b/tests/ui/lint/lint-renamed-cmdline.stderr
@@ -1,23 +1,27 @@
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
 
 warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
+   = help: use the new name `bare_trait_objects`
    = note: requested on the command line with `-D bare_trait_object`
 
 error: unused variable: `unused`
-  --> $DIR/lint-renamed-cmdline.rs:8:17
+  --> $DIR/lint-renamed-cmdline.rs:9:17
    |
 LL | fn main() { let unused = (); }
    |                 ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
    |
 note: the lint level is defined here
-  --> $DIR/lint-renamed-cmdline.rs:7:8
+  --> $DIR/lint-renamed-cmdline.rs:8:8
    |
 LL | #[deny(unused)]
    |        ^^^^^^
diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr
index a11ee769c7c..85852782222 100644
--- a/tests/ui/lint/lint-unexported-no-mangle.stderr
+++ b/tests/ui/lint/lint-unexported-no-mangle.stderr
@@ -1,6 +1,7 @@
 warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
    |
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs
new file mode 100644
index 00000000000..c7f8d434c04
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags:-A unknown-lints -D bogus -D dead_cod
+
+fn main() { }
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
new file mode 100644
index 00000000000..31bc2047356
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
@@ -0,0 +1,9 @@
+// compile-flags:-D unknown-lints -D bogus -D dead_cod
+
+// error-pattern:unknown lint: `bogus`
+// error-pattern:requested on the command line with `-D bogus`
+// error-pattern:requested on the command line with `-D dead_cod`
+// error-pattern:requested on the command line with `-D unknown-lints`
+// error-pattern:did you mean: `dead_code`
+
+fn main() { }
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr
new file mode 100644
index 00000000000..677b5edc894
--- /dev/null
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr
@@ -0,0 +1,31 @@
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+   = note: requested on the command line with `-D unknown-lints`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs
index 7f3f55fbad0..81539cb6dc1 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline.rs
+++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs
@@ -1,7 +1,9 @@
+// check-pass
 // compile-flags:-D bogus -D dead_cod
 
 // error-pattern:unknown lint: `bogus`
 // error-pattern:requested on the command line with `-D bogus`
+// error-pattern:`#[warn(unknown_lints)]` on by default
 // error-pattern:unknown lint: `dead_cod`
 // error-pattern:requested on the command line with `-D dead_cod`
 // error-pattern:did you mean: `dead_code`
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr
index 3855d552792..10db76ac4f1 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr
+++ b/tests/ui/lint/lint-unknown-lint-cmdline.stderr
@@ -1,21 +1,31 @@
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
+   = note: `#[warn(unknown_lints)]` on by default
 
-error[E0602]: unknown lint: `dead_cod`
+warning[E0602]: unknown lint: `dead_cod`
    |
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error[E0602]: unknown lint: `bogus`
+warning[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error[E0602]: unknown lint: `dead_cod`
+warning[E0602]: unknown lint: `dead_cod`
    |
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error: aborting due to 4 previous errors
+warning[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+warning[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+warning: 6 warnings emitted
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs
index 92d985948ec..7745d4ef4c3 100644
--- a/tests/ui/lint/reference_casting.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -36,6 +36,10 @@ unsafe fn ref_to_mut() {
     //~^ ERROR casting `&T` to `&mut T` is undefined behavior
     let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
     //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *std::cell::UnsafeCell::raw_get(
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+        num as *const i32 as *const std::cell::UnsafeCell<i32>
+    );
 
     let deferred = num as *const i32 as *mut i32;
     let _num = &mut *deferred;
@@ -50,6 +54,16 @@ unsafe fn ref_to_mut() {
         &mut *((this as *const _) as *mut _)
         //~^ ERROR casting `&T` to `&mut T` is undefined behavior
     }
+
+    fn as_mut<T>(x: &T) -> &mut T {
+        unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    }
+
+    fn as_mut_i32(x: &i32) -> &mut i32 {
+        unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    }
 }
 
 unsafe fn assign_to_ref() {
@@ -111,6 +125,20 @@ unsafe fn no_warn() {
     let mut value = 3;
     let value: *const i32 = &mut value;
     *(value as *const i16 as *mut i16) = 42;
+
+    fn safe_as_mut<T>(x: &std::cell::UnsafeCell<T>) -> &mut T {
+        unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+    }
+
+    fn cell_as_mut(x: &std::cell::Cell<i32>) -> &mut i32 {
+        unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+    }
+
+    #[repr(transparent)]
+    struct DoesContainUnsafeCell(std::cell::UnsafeCell<i32>);
+    fn safe_as_mut2(x: &DoesContainUnsafeCell) -> &mut DoesContainUnsafeCell {
+        unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr
index 47b95460ec3..1189942c809 100644
--- a/tests/ui/lint/reference_casting.stderr
+++ b/tests/ui/lint/reference_casting.stderr
@@ -80,7 +80,19 @@ LL |     let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:41:16
+  --> $DIR/reference_casting.rs:39:16
+   |
+LL |       let _num = &mut *std::cell::UnsafeCell::raw_get(
+   |  ________________^
+LL | |
+LL | |         num as *const i32 as *const std::cell::UnsafeCell<i32>
+LL | |     );
+   | |_____^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
+
+error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:45:16
    |
 LL |     let deferred = num as *const i32 as *mut i32;
    |                    ----------------------------- casting happend here
@@ -90,7 +102,7 @@ LL |     let _num = &mut *deferred;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:44:16
+  --> $DIR/reference_casting.rs:48:16
    |
 LL |     let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32;
    |                    ---------------------------------------------------------------------------- casting happend here
@@ -100,7 +112,7 @@ LL |     let _num = &mut *deferred;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:46:16
+  --> $DIR/reference_casting.rs:50:16
    |
 LL |     let _num = &mut *(num as *const _ as usize as *mut i32);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,15 +120,31 @@ LL |     let _num = &mut *(num as *const _ as usize as *mut i32);
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:50:9
+  --> $DIR/reference_casting.rs:54:9
    |
 LL |         &mut *((this as *const _) as *mut _)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
+error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:59:18
+   |
+LL |         unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
+
+error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:64:18
+   |
+LL |         unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
+
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:60:5
+  --> $DIR/reference_casting.rs:74:5
    |
 LL |     *(a as *const _ as *mut _) = String::from("Replaced");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +152,7 @@ LL |     *(a as *const _ as *mut _) = String::from("Replaced");
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:62:5
+  --> $DIR/reference_casting.rs:76:5
    |
 LL |     *(a as *const _ as *mut String) += " world";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +160,7 @@ LL |     *(a as *const _ as *mut String) += " world";
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:64:5
+  --> $DIR/reference_casting.rs:78:5
    |
 LL |     *std::ptr::from_ref(num).cast_mut() += 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -140,7 +168,7 @@ LL |     *std::ptr::from_ref(num).cast_mut() += 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:66:5
+  --> $DIR/reference_casting.rs:80:5
    |
 LL |     *std::ptr::from_ref({ num }).cast_mut() += 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +176,7 @@ LL |     *std::ptr::from_ref({ num }).cast_mut() += 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:68:5
+  --> $DIR/reference_casting.rs:82:5
    |
 LL |     *{ std::ptr::from_ref(num) }.cast_mut() += 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +184,7 @@ LL |     *{ std::ptr::from_ref(num) }.cast_mut() += 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:70:5
+  --> $DIR/reference_casting.rs:84:5
    |
 LL |     *(std::ptr::from_ref({ num }) as *mut i32) += 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -164,7 +192,7 @@ LL |     *(std::ptr::from_ref({ num }) as *mut i32) += 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:72:5
+  --> $DIR/reference_casting.rs:86:5
    |
 LL |     *std::mem::transmute::<_, *mut i32>(num) += 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,7 +200,7 @@ LL |     *std::mem::transmute::<_, *mut i32>(num) += 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:74:5
+  --> $DIR/reference_casting.rs:88:5
    |
 LL | /     std::ptr::write(
 LL | |
@@ -184,7 +212,7 @@ LL | |     );
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:81:5
+  --> $DIR/reference_casting.rs:95:5
    |
 LL |     let value = num as *const i32 as *mut i32;
    |                 ----------------------------- casting happend here
@@ -194,7 +222,7 @@ LL |     *value = 1;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:83:5
+  --> $DIR/reference_casting.rs:97:5
    |
 LL |     *(num as *const i32).cast::<i32>().cast_mut() = 2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +230,7 @@ LL |     *(num as *const i32).cast::<i32>().cast_mut() = 2;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:85:5
+  --> $DIR/reference_casting.rs:99:5
    |
 LL |     *(num as *const _ as usize as *mut i32) = 2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -210,7 +238,7 @@ LL |     *(num as *const _ as usize as *mut i32) = 2;
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:87:5
+  --> $DIR/reference_casting.rs:101:5
    |
 LL |     let value = num as *const i32 as *mut i32;
    |                 ----------------------------- casting happend here
@@ -221,7 +249,7 @@ LL |     std::ptr::write(value, 2);
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:89:5
+  --> $DIR/reference_casting.rs:103:5
    |
 LL |     let value = num as *const i32 as *mut i32;
    |                 ----------------------------- casting happend here
@@ -232,7 +260,7 @@ LL |     std::ptr::write_unaligned(value, 2);
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:91:5
+  --> $DIR/reference_casting.rs:105:5
    |
 LL |     let value = num as *const i32 as *mut i32;
    |                 ----------------------------- casting happend here
@@ -243,12 +271,12 @@ LL |     std::ptr::write_volatile(value, 2);
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
 error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:95:9
+  --> $DIR/reference_casting.rs:109:9
    |
 LL |         *(this as *const _ as *mut _) = a;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
 
-error: aborting due to 29 previous errors
+error: aborting due to 32 previous errors
 
diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr
index 3ac5e96c574..4eff08ead42 100644
--- a/tests/ui/namespace/namespace-mix.stderr
+++ b/tests/ui/namespace/namespace-mix.stderr
@@ -114,6 +114,11 @@ LL |     check(m1::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -128,6 +133,11 @@ LL |     check(m2::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -142,6 +152,11 @@ LL |     check(m2::S);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -156,6 +171,11 @@ LL |     check(xm1::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -170,6 +190,11 @@ LL |     check(xm2::S{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -184,6 +209,11 @@ LL |     check(xm2::S);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -198,6 +228,11 @@ LL |     check(m3::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -212,6 +247,11 @@ LL |     check(m3::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -226,6 +266,11 @@ LL |     check(m4::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -240,6 +285,11 @@ LL |     check(m4::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -254,6 +304,11 @@ LL |     check(xm3::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -268,6 +323,11 @@ LL |     check(xm3::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -282,6 +342,11 @@ LL |     check(xm4::TS{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -296,6 +361,11 @@ LL |     check(xm4::TS);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -310,6 +380,11 @@ LL |     check(m5::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -324,6 +399,11 @@ LL |     check(m5::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -338,6 +418,11 @@ LL |     check(m6::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -352,6 +437,11 @@ LL |     check(m6::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -366,6 +456,11 @@ LL |     check(xm5::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -380,6 +475,11 @@ LL |     check(xm5::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -394,6 +494,11 @@ LL |     check(xm6::US{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -408,6 +513,11 @@ LL |     check(xm6::US);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -422,6 +532,11 @@ LL |     check(m7::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -436,6 +551,11 @@ LL |     check(m8::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -450,6 +570,11 @@ LL |     check(m8::V);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -464,6 +589,11 @@ LL |     check(xm7::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -478,6 +608,11 @@ LL |     check(xm8::V{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -492,6 +627,11 @@ LL |     check(xm8::V);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -506,6 +646,11 @@ LL |     check(m9::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -520,6 +665,11 @@ LL |     check(m9::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -534,6 +684,11 @@ LL |     check(mA::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -548,6 +703,11 @@ LL |     check(mA::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -562,6 +722,11 @@ LL |     check(xm9::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -576,6 +741,11 @@ LL |     check(xm9::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -590,6 +760,11 @@ LL |     check(xmA::TV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -604,6 +779,11 @@ LL |     check(xmA::TV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -618,6 +798,11 @@ LL |     check(mB::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -632,6 +817,11 @@ LL |     check(mB::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -646,6 +836,11 @@ LL |     check(mC::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -660,6 +855,11 @@ LL |     check(mC::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -674,6 +874,11 @@ LL |     check(xmB::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -688,6 +893,11 @@ LL |     check(xmB::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -702,6 +912,11 @@ LL |     check(xmC::UV{});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
@@ -716,6 +931,11 @@ LL |     check(xmC::UV);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/namespace-mix.rs:20:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
   --> $DIR/namespace-mix.rs:21:13
    |
diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs
index 85413acdb14..25bac1ba24b 100644
--- a/tests/ui/nested-ty-params.rs
+++ b/tests/ui/nested-ty-params.rs
@@ -1,4 +1,4 @@
-// error-pattern:can't use generic parameters from outer function
+// error-pattern:can't use generic parameters from outer item
 fn hd<U>(v: Vec<U> ) -> U {
     fn hd1(w: [U]) -> U { return w[0]; }
 
diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/nested-ty-params.stderr
index 8f4746f5ec3..a9cdec66719 100644
--- a/tests/ui/nested-ty-params.stderr
+++ b/tests/ui/nested-ty-params.stderr
@@ -1,22 +1,22 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/nested-ty-params.rs:3:16
    |
 LL | fn hd<U>(v: Vec<U> ) -> U {
-   |       - type parameter from outer function
+   |       - type parameter from outer item
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |           -    ^ use of generic parameter from outer function
+   |           -    ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<U>`
+   |           help: try introducing a local generic parameter here: `<U>`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/nested-ty-params.rs:3:23
    |
 LL | fn hd<U>(v: Vec<U> ) -> U {
-   |       - type parameter from outer function
+   |       - type parameter from outer item
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |           -           ^ use of generic parameter from outer function
+   |           -           ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<U>`
+   |           help: try introducing a local generic parameter here: `<U>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/never_type/feature-gate-never_type_fallback.stderr b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
index 2db1cc4b776..56aafbb4ce8 100644
--- a/tests/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -8,6 +8,11 @@ LL |     foo(panic!())
    |     |   this tail expression is of type `()`
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/feature-gate-never_type_fallback.rs:7:1
+   |
+LL | trait T {}
+   | ^^^^^^^
 note: required by a bound in `foo`
   --> $DIR/feature-gate-never_type_fallback.rs:13:16
    |
diff --git a/tests/ui/never_type/impl_trait_fallback3.stderr b/tests/ui/never_type/impl_trait_fallback3.stderr
index 5d5d216fb9b..821d141569e 100644
--- a/tests/ui/never_type/impl_trait_fallback3.stderr
+++ b/tests/ui/never_type/impl_trait_fallback3.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn a() -> Foo {
    |           ^^^ the trait `T` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl_trait_fallback3.rs:5:1
+   |
+LL | trait T {
+   | ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/never_type/impl_trait_fallback4.stderr b/tests/ui/never_type/impl_trait_fallback4.stderr
index f2e216e9044..67421ba8da7 100644
--- a/tests/ui/never_type/impl_trait_fallback4.stderr
+++ b/tests/ui/never_type/impl_trait_fallback4.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn foo() -> impl T {
    |             ^^^^^^ the trait `T` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl_trait_fallback4.rs:3:1
+   |
+LL | trait T {
+   | ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/on-unimplemented/on-trait.stderr b/tests/ui/on-unimplemented/on-trait.stderr
index 4b040f1ac5a..4847a1a5a61 100644
--- a/tests/ui/on-unimplemented/on-trait.stderr
+++ b/tests/ui/on-unimplemented/on-trait.stderr
@@ -5,6 +5,11 @@ LL |     let y: Option<Vec<u8>> = collect(x.iter()); // this should give approxi
    |                              ^^^^^^^ a collection of type `Option<Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
    |
    = help: the trait `MyFromIterator<&u8>` is not implemented for `Option<Vec<u8>>`
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-trait.rs:17:1
+   |
+LL | trait MyFromIterator<A> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `collect`
   --> $DIR/on-trait.rs:22:39
    |
@@ -18,6 +23,11 @@ LL |     let x: String = foobar();
    |                     ^^^^^^ test error `String` with `u8` `_` `u32` in `Foo`
    |
    = help: the trait `Foo<u8, _, u32>` is not implemented for `String`
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-trait.rs:7:3
+   |
+LL |   pub trait Foo<Bar, Baz, Quux> {}
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `foobar`
   --> $DIR/on-trait.rs:12:24
    |
diff --git a/tests/ui/on-unimplemented/parent-label.stderr b/tests/ui/on-unimplemented/parent-label.stderr
index 8cd7412fd9d..101a41512d2 100644
--- a/tests/ui/on-unimplemented/parent-label.stderr
+++ b/tests/ui/on-unimplemented/parent-label.stderr
@@ -8,6 +8,11 @@ LL |         f(Foo {});
    |         |
    |         required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -24,6 +29,11 @@ LL |             f(Foo {});
    |             |
    |             required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -41,6 +51,11 @@ LL |             f(Foo {});
    |             |
    |             required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
@@ -58,6 +73,11 @@ LL |     f(Foo {});
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/parent-label.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/parent-label.rs:10:9
    |
diff --git a/tests/ui/parser/default-unmatched.stderr b/tests/ui/parser/default-unmatched.stderr
index 331e003f63c..de142411d69 100644
--- a/tests/ui/parser/default-unmatched.stderr
+++ b/tests/ui/parser/default-unmatched.stderr
@@ -11,6 +11,8 @@ error: expected item, found reserved keyword `do`
    |
 LL |     default do
    |             ^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr
index 755addf1452..a57cc075ccc 100644
--- a/tests/ui/parser/impl-parsing.stderr
+++ b/tests/ui/parser/impl-parsing.stderr
@@ -35,6 +35,8 @@ error: expected item, found keyword `unsafe`
    |
 LL | default unsafe FAIL
    |         ^^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/parser/issue-101477-enum.stderr b/tests/ui/parser/issue-101477-enum.stderr
index 1edca391e8f..94130671f1c 100644
--- a/tests/ui/parser/issue-101477-enum.stderr
+++ b/tests/ui/parser/issue-101477-enum.stderr
@@ -11,6 +11,8 @@ error: expected item, found `==`
    |
 LL |     B == 2
    |       ^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs
new file mode 100644
index 00000000000..3b6f4304369
--- /dev/null
+++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs
@@ -0,0 +1 @@
+ 5 //~ ERROR expected item, found `5`
diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr
new file mode 100644
index 00000000000..0789c4548a0
--- /dev/null
+++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr
@@ -0,0 +1,10 @@
+error: expected item, found `5`
+  --> $DIR/issue-113110-non-item-at-module-root.rs:1:2
+   |
+LL |  5
+   |  ^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/issues/issue-17904-2.stderr b/tests/ui/parser/issues/issue-17904-2.stderr
index 9c7fdf6ccb4..7185a5e5752 100644
--- a/tests/ui/parser/issues/issue-17904-2.stderr
+++ b/tests/ui/parser/issues/issue-17904-2.stderr
@@ -3,6 +3,8 @@ error: expected item, found keyword `where`
    |
 LL | struct Bar<T> { x: T } where T: Copy
    |                        ^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/issues/issue-43196.stderr b/tests/ui/parser/issues/issue-43196.stderr
index 4f7ed5cc6fd..15bbb158cd1 100644
--- a/tests/ui/parser/issues/issue-43196.stderr
+++ b/tests/ui/parser/issues/issue-43196.stderr
@@ -11,6 +11,8 @@ error: expected item, found `|`
    |
 LL | |
    | ^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-62913.stderr b/tests/ui/parser/issues/issue-62913.stderr
index 6f385e8dc17..c33e4683728 100644
--- a/tests/ui/parser/issues/issue-62913.stderr
+++ b/tests/ui/parser/issues/issue-62913.stderr
@@ -17,6 +17,8 @@ error: expected item, found `"\u\"`
    |
 LL | "\u\"
    | ^^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/issues/issue-68890.stderr b/tests/ui/parser/issues/issue-68890.stderr
index 2a3bf6b41f0..0d7b53a67c5 100644
--- a/tests/ui/parser/issues/issue-68890.stderr
+++ b/tests/ui/parser/issues/issue-68890.stderr
@@ -15,6 +15,8 @@ error: expected item, found `)`
    |
 LL | enum e{A((?'a a+?+l))}
    |                     ^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/shebang/shebang-doc-comment.stderr b/tests/ui/parser/shebang/shebang-doc-comment.stderr
index 2227d45ec5a..a36b2a2f72b 100644
--- a/tests/ui/parser/shebang/shebang-doc-comment.stderr
+++ b/tests/ui/parser/shebang/shebang-doc-comment.stderr
@@ -3,6 +3,8 @@ error: expected item, found `[`
    |
 LL | [allow(unused_variables)]
    | ^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/virtual-structs.stderr b/tests/ui/parser/virtual-structs.stderr
index a5211d83f84..268fc105796 100644
--- a/tests/ui/parser/virtual-structs.stderr
+++ b/tests/ui/parser/virtual-structs.stderr
@@ -3,6 +3,8 @@ error: expected item, found reserved keyword `virtual`
    |
 LL | virtual struct SuperStruct {
    | ^^^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pattern/issue-114896.rs b/tests/ui/pattern/issue-114896.rs
new file mode 100644
index 00000000000..cde37f658d6
--- /dev/null
+++ b/tests/ui/pattern/issue-114896.rs
@@ -0,0 +1,7 @@
+fn main() {
+    fn x(a: &char) {
+        let &b = a;
+        b.make_ascii_uppercase();
+//~^ cannot borrow `b` as mutable, as it is not declared as mutable
+    }
+}
diff --git a/tests/ui/pattern/issue-114896.stderr b/tests/ui/pattern/issue-114896.stderr
new file mode 100644
index 00000000000..ffeb7bc1365
--- /dev/null
+++ b/tests/ui/pattern/issue-114896.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/issue-114896.rs:4:9
+   |
+LL |         let &b = a;
+   |             -- help: consider changing this to be mutable: `&(mut b)`
+LL |         b.make_ascii_uppercase();
+   |         ^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/privacy/private-bounds-locally-allowed.rs b/tests/ui/privacy/private-bounds-locally-allowed.rs
new file mode 100644
index 00000000000..96a007a64f6
--- /dev/null
+++ b/tests/ui/privacy/private-bounds-locally-allowed.rs
@@ -0,0 +1,7 @@
+// check-pass
+// compile-flags: --crate-type=lib
+
+#[allow(private_bounds)]
+pub trait Foo: FooImpl {}
+
+trait FooImpl {}
diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs
index e35aaec5b3b..c6c5561c3c4 100644
--- a/tests/ui/privacy/unnameable_types.rs
+++ b/tests/ui/privacy/unnameable_types.rs
@@ -20,10 +20,10 @@ mod m {
     }
 }
 
-pub trait Voldemort<T> {}
+pub trait Unnameable<T> {}
 
-impl Voldemort<m::PubStruct> for i32 {}
-impl Voldemort<m::PubE> for i32 {}
-impl<T> Voldemort<T> for u32 where T: m::PubTr {}
+impl Unnameable<m::PubStruct> for i32 {}
+impl Unnameable<m::PubE> for i32 {}
+impl<T> Unnameable<T> for u32 where T: m::PubTr {}
 
 fn main() {}
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index 8a8246376fe..8716defa17a 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Project` is not satisfied
    |
 LL | pub fn uwu() -> <() as Project>::Assoc {}
    |                 ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pub/pub-restricted-error-fn.stderr b/tests/ui/pub/pub-restricted-error-fn.stderr
index 0511a821a7a..ca5d8e1b58e 100644
--- a/tests/ui/pub/pub-restricted-error-fn.stderr
+++ b/tests/ui/pub/pub-restricted-error-fn.stderr
@@ -11,6 +11,8 @@ error: expected item, found `(`
    |
 LL | pub(crate) () fn foo() {}
    |            ^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/bad-type-env-capture.stderr b/tests/ui/resolve/bad-type-env-capture.stderr
index b6282c2d070..941b6b7a68c 100644
--- a/tests/ui/resolve/bad-type-env-capture.stderr
+++ b/tests/ui/resolve/bad-type-env-capture.stderr
@@ -1,12 +1,12 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/bad-type-env-capture.rs:2:15
    |
 LL | fn foo<T>() {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(b: T) { }
-   |           -   ^ use of generic parameter from outer function
+   |           -   ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
new file mode 100644
index 00000000000..4f853829279
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -0,0 +1,28 @@
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:12:20
+   |
+LL | fn outer<T: Tr>() { // outer function
+   |          - type parameter from outer item
+LL |     const K: u32 = T::C;
+   |                    ^^^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
+   |
+LL | impl<T> Tr for T { // outer impl block
+   |      - type parameter from outer item
+LL |     const C: u32 = {
+LL |         const I: u32 = T::C;
+   |                        ^^^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
+   |
+LL | struct S<T: Tr>(U32<{ // outer struct
+   |          - type parameter from outer item
+LL |     const _: u32 = T::C;
+   |                    ^^^^ use of generic parameter from outer item
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
new file mode 100644
index 00000000000..1cb55842bc6
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -0,0 +1,34 @@
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:12:20
+   |
+LL | fn outer<T: Tr>() { // outer function
+   |          - type parameter from outer item
+LL |     const K: u32 = T::C;
+   |            -       ^^^^ use of generic parameter from outer item
+   |            |
+   |            help: try introducing a local generic parameter here: `<T>`
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
+   |
+LL | impl<T> Tr for T { // outer impl block
+   |      - type parameter from outer item
+LL |     const C: u32 = {
+LL |         const I: u32 = T::C;
+   |                -       ^^^^ use of generic parameter from outer item
+   |                |
+   |                help: try introducing a local generic parameter here: `<T>`
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
+   |
+LL | struct S<T: Tr>(U32<{ // outer struct
+   |          - type parameter from outer item
+LL |     const _: u32 = T::C;
+   |            -       ^^^^ use of generic parameter from outer item
+   |            |
+   |            help: try introducing a local generic parameter here: `<T>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs
new file mode 100644
index 00000000000..e5647d72cba
--- /dev/null
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs
@@ -0,0 +1,39 @@
+// Regression test for issue #115720.
+// If a const item contains generic params from an outer items, only suggest
+// turning the const item generic if the feature `generic_const_items` is enabled.
+
+// revisions: default generic_const_items
+
+#![cfg_attr(generic_const_items, feature(generic_const_items))]
+#![feature(generic_const_exprs)] // only used for the test case "outer struct"
+#![allow(incomplete_features)]
+
+fn outer<T: Tr>() { // outer function
+    const K: u32 = T::C;
+    //~^ ERROR can't use generic parameters from outer item
+    //[generic_const_items]~| HELP try introducing a local generic parameter here
+}
+
+impl<T> Tr for T { // outer impl block
+    const C: u32 = {
+        const I: u32 = T::C;
+        //~^ ERROR can't use generic parameters from outer item
+        //[generic_const_items]~| HELP try introducing a local generic parameter here
+        I
+    };
+}
+
+struct S<T: Tr>(U32<{ // outer struct
+    const _: u32 = T::C;
+    //~^ ERROR can't use generic parameters from outer item
+    //[generic_const_items]~| HELP try introducing a local generic parameter here
+    0
+}>);
+
+trait Tr {
+    const C: u32;
+}
+
+struct U32<const N: u32>;
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs
index 942d6b9a568..de3e73437f0 100644
--- a/tests/ui/resolve/issue-12796.rs
+++ b/tests/ui/resolve/issue-12796.rs
@@ -1,7 +1,7 @@
 trait Trait {
     fn outer(&self) {
         fn inner(_: &Self) {
-            //~^ ERROR can't use generic parameters from outer function
+            //~^ ERROR can't use generic parameters from outer item
         }
     }
 }
diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr
index a01fd2d6542..ef59d00360b 100644
--- a/tests/ui/resolve/issue-12796.stderr
+++ b/tests/ui/resolve/issue-12796.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-12796.rs:3:22
    |
 LL |         fn inner(_: &Self) {
    |                      ^^^^
    |                      |
-   |                      use of generic parameter from outer function
+   |                      use of generic parameter from outer item
    |                      can't use `Self` here
 
 error: aborting due to previous error
diff --git a/tests/ui/resolve/issue-3021-c.rs b/tests/ui/resolve/issue-3021-c.rs
index 94ed1fdf781..bd21d124423 100644
--- a/tests/ui/resolve/issue-3021-c.rs
+++ b/tests/ui/resolve/issue-3021-c.rs
@@ -1,8 +1,8 @@
 fn siphash<T>() {
 
     trait U {
-        fn g(&self, x: T) -> T;  //~ ERROR can't use generic parameters from outer function
-        //~^ ERROR can't use generic parameters from outer function
+        fn g(&self, x: T) -> T;  //~ ERROR can't use generic parameters from outer item
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/resolve/issue-3021-c.stderr b/tests/ui/resolve/issue-3021-c.stderr
index 5176efc3a6b..537bbaf7b6a 100644
--- a/tests/ui/resolve/issue-3021-c.stderr
+++ b/tests/ui/resolve/issue-3021-c.stderr
@@ -1,24 +1,24 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3021-c.rs:4:24
    |
 LL | fn siphash<T>() {
-   |            - type parameter from outer function
+   |            - type parameter from outer item
 LL |
 LL |     trait U {
-   |            - help: try using a local generic parameter instead: `<T>`
+   |            - help: try introducing a local generic parameter here: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |                        ^ use of generic parameter from outer function
+   |                        ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-3021-c.rs:4:30
    |
 LL | fn siphash<T>() {
-   |            - type parameter from outer function
+   |            - type parameter from outer item
 LL |
 LL |     trait U {
-   |            - help: try using a local generic parameter instead: `<T>`
+   |            - help: try introducing a local generic parameter here: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |                              ^ use of generic parameter from outer function
+   |                              ^ use of generic parameter from outer item
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs b/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
index ce45f630e48..4fa3f12d024 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.rs
@@ -1,7 +1,7 @@
 unsafe fn foo<A>() {
     extern "C" {
         static baz: *const A;
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 
     let bar: *const u64 = core::mem::transmute(&baz);
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
index 6bbf76dd1fb..3e9c3fd11b7 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
@@ -1,11 +1,11 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65025-extern-static-parent-generics.rs:3:28
    |
 LL | unsafe fn foo<A>() {
-   |               - type parameter from outer function
+   |               - type parameter from outer item
 LL |     extern "C" {
 LL |         static baz: *const A;
-   |                            ^ use of generic parameter from outer function
+   |                            ^ use of generic parameter from outer item
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.rs b/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
index f96c04841dd..bc99584a8d2 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.rs
@@ -1,26 +1,26 @@
 fn f<T>() {
     extern "C" {
         static a: *const T;
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 fn g<T: Default>() {
     static a: *const T = Default::default();
-    //~^ ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
 }
 
 fn h<const N: usize>() {
     extern "C" {
         static a: [u8; N];
-        //~^ ERROR can't use generic parameters from outer function
+        //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 fn i<const N: usize>() {
     static a: [u8; N] = [0; N];
-    //~^ ERROR can't use generic parameters from outer function
-    //~| ERROR can't use generic parameters from outer function
+    //~^ ERROR can't use generic parameters from outer item
+    //~| ERROR can't use generic parameters from outer item
 }
 
 fn main() {}
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
index 7ed572f80b8..f1fe1a6002c 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -1,44 +1,44 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:3:26
    |
 LL | fn f<T>() {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     extern "C" {
 LL |         static a: *const T;
-   |                          ^ use of generic parameter from outer function
+   |                          ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:9:22
    |
 LL | fn g<T: Default>() {
-   |      - type parameter from outer function
+   |      - type parameter from outer item
 LL |     static a: *const T = Default::default();
-   |                      ^ use of generic parameter from outer function
+   |                      ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:15:24
    |
 LL | fn h<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     extern "C" {
 LL |         static a: [u8; N];
-   |                        ^ use of generic parameter from outer function
+   |                        ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:20
    |
 LL | fn i<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
-   |                    ^ use of generic parameter from outer function
+   |                    ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:29
    |
 LL | fn i<const N: usize>() {
-   |            - const parameter from outer function
+   |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
-   |                             ^ use of generic parameter from outer function
+   |                             ^ use of generic parameter from outer item
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs b/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
index c77a66524f7..2d5f34c62a6 100644
--- a/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
+++ b/tests/ui/resolve/resolve-type-param-in-item-in-trait.rs
@@ -6,7 +6,7 @@ trait TraitA<A> {
     fn outer(&self) {
         enum Foo<B> {
             Variance(A)
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
         }
     }
 }
@@ -14,21 +14,21 @@ trait TraitA<A> {
 trait TraitB<A> {
     fn outer(&self) {
         struct Foo<B>(A);
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 trait TraitC<A> {
     fn outer(&self) {
         struct Foo<B> { a: A }
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
 trait TraitD<A> {
     fn outer(&self) {
         fn foo<B>(a: A) { }
-                //~^ ERROR can't use generic parameters from outer function
+                //~^ ERROR can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
index 0a6d1cc3bcd..1ab56fdc504 100644
--- a/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
+++ b/tests/ui/resolve/resolve-type-param-in-item-in-trait.stderr
@@ -1,46 +1,46 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:8:22
    |
 LL | trait TraitA<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         enum Foo<B> {
-   |                  - help: try using a local generic parameter instead: `A,`
+   |                  - help: try introducing a local generic parameter here: `A,`
 LL |             Variance(A)
-   |                      ^ use of generic parameter from outer function
+   |                      ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:16:23
    |
 LL | trait TraitB<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         struct Foo<B>(A);
-   |                    -  ^ use of generic parameter from outer function
+   |                    -  ^ use of generic parameter from outer item
    |                    |
-   |                    help: try using a local generic parameter instead: `A,`
+   |                    help: try introducing a local generic parameter here: `A,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
    |
 LL | trait TraitC<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         struct Foo<B> { a: A }
-   |                    -       ^ use of generic parameter from outer function
+   |                    -       ^ use of generic parameter from outer item
    |                    |
-   |                    help: try using a local generic parameter instead: `A,`
+   |                    help: try introducing a local generic parameter here: `A,`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
    |
 LL | trait TraitD<A> {
-   |              - type parameter from outer function
+   |              - type parameter from outer item
 LL |     fn outer(&self) {
 LL |         fn foo<B>(a: A) { }
-   |                -     ^ use of generic parameter from outer function
+   |                -     ^ use of generic parameter from outer item
    |                |
-   |                help: try using a local generic parameter instead: `A,`
+   |                help: try introducing a local generic parameter here: `A,`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed
new file mode 100644
index 00000000000..fc68884fe9c
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+// compile-flags: --cfg=whatever -Aunused
+
+use y::z;
+#[cfg(whatever)]
+use y::Whatever;
+
+mod y {
+    pub(crate) fn z() {}
+    pub(crate) struct Whatever;
+}
+
+fn main() {
+    z();
+    //~^ ERROR cannot find function `z` in this scope
+}
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs
new file mode 100644
index 00000000000..38a1095703b
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+// compile-flags: --cfg=whatever -Aunused
+
+#[cfg(whatever)]
+use y::Whatever;
+
+mod y {
+    pub(crate) fn z() {}
+    pub(crate) struct Whatever;
+}
+
+fn main() {
+    z();
+    //~^ ERROR cannot find function `z` in this scope
+}
diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr
new file mode 100644
index 00000000000..d3574851d5c
--- /dev/null
+++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr
@@ -0,0 +1,14 @@
+error[E0425]: cannot find function `z` in this scope
+  --> $DIR/suggest-import-without-clobbering-attrs.rs:13:5
+   |
+LL |     z();
+   |     ^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use y::z;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs
index eccb315feb1..f4dfa4c40ab 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.rs
+++ b/tests/ui/resolve/use-self-in-inner-fn.rs
@@ -4,9 +4,9 @@ impl A {
 //~^ NOTE `Self` type implicitly declared here, by this `impl`
     fn banana(&mut self) {
         fn peach(this: &Self) {
-        //~^ ERROR can't use generic parameters from outer function
-        //~| NOTE use of generic parameter from outer function
-        //~| NOTE use a type here instead
+        //~^ ERROR can't use generic parameters from outer item
+        //~| NOTE use of generic parameter from outer item
+        //~| NOTE refer to the type directly here instead
         }
     }
 }
diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr
index 96609349924..832aaacaf49 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.stderr
+++ b/tests/ui/resolve/use-self-in-inner-fn.stderr
@@ -1,4 +1,4 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/use-self-in-inner-fn.rs:6:25
    |
 LL | impl A {
@@ -7,8 +7,8 @@ LL | impl A {
 LL |         fn peach(this: &Self) {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer function
-   |                         use a type here instead
+   |                         use of generic parameter from outer item
+   |                         refer to the type directly here instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs
new file mode 100644
index 00000000000..855bbb2e992
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(const_trait_impl, effects)]
+
+pub const fn owo() {}
+
+fn main() {
+    let _ = owo;
+}
diff --git a/tests/ui/sanitize/cfg.rs b/tests/ui/sanitize/cfg.rs
index c0f08a6d1e5..523de1ceaee 100644
--- a/tests/ui/sanitize/cfg.rs
+++ b/tests/ui/sanitize/cfg.rs
@@ -2,19 +2,19 @@
 // the `#[cfg(sanitize = "option")]` attribute is configured.
 
 // needs-sanitizer-support
-// needs-sanitizer-address
-// needs-sanitizer-cfi
-// needs-sanitizer-kcfi
-// needs-sanitizer-leak
-// needs-sanitizer-memory
-// needs-sanitizer-thread
 // check-pass
-// revisions: address leak memory thread
+// revisions: address cfi kcfi leak memory thread
+//[address]needs-sanitizer-address
 //[address]compile-flags: -Zsanitizer=address --cfg address
-//[cfi]compile-flags:     -Zsanitizer=cfi     --cfg cfi
+//[cfi]needs-sanitizer-cfi
+//[cfi]compile-flags:     -Zsanitizer=cfi     --cfg cfi -Clto
+//[kcfi]needs-sanitizer-kcfi
 //[kcfi]compile-flags:    -Zsanitizer=kcfi    --cfg kcfi
+//[leak]needs-sanitizer-leak
 //[leak]compile-flags:    -Zsanitizer=leak    --cfg leak
+//[memory]needs-sanitizer-memory
 //[memory]compile-flags:  -Zsanitizer=memory  --cfg memory
+//[thread]needs-sanitizer-thread
 //[thread]compile-flags:  -Zsanitizer=thread  --cfg thread
 
 #![feature(cfg_sanitize)]
diff --git a/tests/ui/span/issue-29595.stderr b/tests/ui/span/issue-29595.stderr
index 92445e40731..7d603cdbfe5 100644
--- a/tests/ui/span/issue-29595.stderr
+++ b/tests/ui/span/issue-29595.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied
    |
 LL |     let a: u8 = Tr::C;
    |                 ^^^^^ the trait `Tr` is not implemented for `u8`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-29595.rs:1:1
+   |
+LL | trait Tr {
+   | ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/specialization/issue-38091.stderr b/tests/ui/specialization/issue-38091.stderr
index f2210a40719..4d840482b46 100644
--- a/tests/ui/specialization/issue-38091.stderr
+++ b/tests/ui/specialization/issue-38091.stderr
@@ -14,6 +14,11 @@ error[E0277]: the trait bound `(): Valid` is not satisfied
 LL |     default type Ty = ();
    |                       ^^ the trait `Valid` is not implemented for `()`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-38091.rs:20:1
+   |
+LL | trait Valid {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Iterate::Ty`
   --> $DIR/issue-38091.rs:5:14
    |
diff --git a/tests/ui/suggestions/issue-89333.stderr b/tests/ui/suggestions/issue-89333.stderr
index f73f1147d5d..4739f11ddad 100644
--- a/tests/ui/suggestions/issue-89333.stderr
+++ b/tests/ui/suggestions/issue-89333.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> &'a _: Trait` is not satisfied
 LL |     test(&|| 0);
    |     ^^^^ the trait `for<'a> Trait` is not implemented for `&'a _`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-89333.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `test`
   --> $DIR/issue-89333.rs:11:55
    |
diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout
index 7bddc925996..af7f2b67152 100644
--- a/tests/ui/thir-print/thir-flat-const-variant.stdout
+++ b/tests/ui/thir-print/thir-flat-const-variant.stdout
@@ -1,7 +1,11 @@
 DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -46,7 +50,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -60,7 +68,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -72,7 +84,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -86,7 +102,11 @@ Thir {
 DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -131,7 +151,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -145,7 +169,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -157,7 +185,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -171,7 +203,11 @@ Thir {
 DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -216,7 +252,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -230,7 +270,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -242,7 +286,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -256,7 +304,11 @@ Thir {
 DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4):
 Thir {
     body_type: Const(
-        Foo,
+        Adt(
+            Foo,
+            [
+            ],
+        ),
     ),
     arms: [],
     blocks: [],
@@ -301,7 +353,11 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -315,7 +371,11 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -327,7 +387,11 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Foo,
+            ty: Adt(
+                Foo,
+                [
+                ],
+            ),
             temp_lifetime: Some(
                 Node(3),
             ),
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 3fc130f0176..0e21b98307b 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -1,13 +1,13 @@
 DefId(0:16 ~ thir_tree_match[fcf8]::has_match):
 params: [
     Param {
-        ty: Foo
+        ty: Adt(Foo, [])
         ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
         self_kind: None
         hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1))
         param: Some( 
             Pat: {
-                ty: Foo
+                ty: Adt(Foo, [])
                 span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
                 kind: PatKind {
                     Binding {
@@ -15,7 +15,7 @@ params: [
                         name: "foo"
                         mode: ByValue
                         var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
-                        ty: Foo
+                        ty: Adt(Foo, [])
                         is_primary: true
                         subpattern: None
                     }
@@ -73,7 +73,7 @@ body:
                                                                             Match {
                                                                                 scrutinee:
                                                                                     Expr {
-                                                                                        ty: Foo
+                                                                                        ty: Adt(Foo, [])
                                                                                         temp_lifetime: Some(Node(26))
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
@@ -82,7 +82,7 @@ body:
                                                                                                 lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
                                                                                                 value:
                                                                                                     Expr {
-                                                                                                        ty: Foo
+                                                                                                        ty: Adt(Foo, [])
                                                                                                         temp_lifetime: Some(Node(26))
                                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                                         kind: 
@@ -96,7 +96,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -110,7 +110,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Bar
+                                                                                                                ty: Adt(Bar, [])
                                                                                                                 span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Variant {
@@ -169,7 +169,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -183,7 +183,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Bar
+                                                                                                                ty: Adt(Bar, [])
                                                                                                                 span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Wild
@@ -232,7 +232,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Foo
+                                                                                                ty: Adt(Foo, [])
                                                                                                 span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
diff --git a/tests/ui/trait-bounds/issue-82038.rs b/tests/ui/trait-bounds/issue-82038.rs
new file mode 100644
index 00000000000..11de714faf0
--- /dev/null
+++ b/tests/ui/trait-bounds/issue-82038.rs
@@ -0,0 +1,9 @@
+// Failed bound `bool: Foo` must not point at the `Self: Clone` line
+
+trait Foo {
+    fn my_method() where Self: Clone;
+}
+
+fn main() {
+    <bool as Foo>::my_method(); //~ERROR [E0277]
+}
diff --git a/tests/ui/trait-bounds/issue-82038.stderr b/tests/ui/trait-bounds/issue-82038.stderr
new file mode 100644
index 00000000000..30bb4a0a850
--- /dev/null
+++ b/tests/ui/trait-bounds/issue-82038.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `bool: Foo` is not satisfied
+  --> $DIR/issue-82038.rs:8:6
+   |
+LL |     <bool as Foo>::my_method();
+   |      ^^^^ the trait `Foo` is not implemented for `bool`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-82038.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr b/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
index 61237a63e32..530264b344a 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-in-fns.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u32: Trait` is not satisfied
 LL | fn explode(x: Foo<u32>) {}
    |               ^^^^^^^^ the trait `Trait` is not implemented for `u32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-fns.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-in-fns.rs:3:14
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `f32: Trait` is not satisfied
 LL | fn kaboom(y: Bar<f32>) {}
    |              ^^^^^^^^ the trait `Trait` is not implemented for `f32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-fns.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums-in-fns.rs:7:12
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr b/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
index 8a43742260b..372bbabbd86 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-in-impls.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u16: Trait` is not satisfied
 LL | impl PolyTrait<Foo<u16>> for Struct {
    |      ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u16`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-in-impls.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-in-impls.rs:3:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
index 20bbe69c059..01cf76c62d5 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL |     let baz: Foo<usize> = loop { };
    |              ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-locals.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-locals.rs:5:14
    |
@@ -16,6 +21,11 @@ error[E0277]: the trait bound `{integer}: Trait` is not satisfied
 LL |         x: 3
    |            ^ the trait `Trait` is not implemented for `{integer}`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-locals.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-locals.rs:5:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
index fda734e8571..fa14aff684d 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL | static X: Foo<usize> = Foo {
    |           ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-static.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums-static.rs:5:14
    |
diff --git a/tests/ui/traits/bound/on-structs-and-enums.stderr b/tests/ui/traits/bound/on-structs-and-enums.stderr
index fe05b86344b..606f764852f 100644
--- a/tests/ui/traits/bound/on-structs-and-enums.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums.stderr
@@ -20,6 +20,11 @@ error[E0277]: the trait bound `isize: Trait` is not satisfied
 LL |     a: Foo<isize>,
    |        ^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums.rs:3:14
    |
@@ -32,6 +37,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
 LL |     Quux(Bar<usize>),
    |          ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums.rs:7:12
    |
@@ -76,6 +86,11 @@ error[E0277]: the trait bound `i32: Trait` is not satisfied
 LL |     Foo<i32>,
    |     ^^^^^^^^ the trait `Trait` is not implemented for `i32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Foo`
   --> $DIR/on-structs-and-enums.rs:3:14
    |
@@ -88,6 +103,11 @@ error[E0277]: the trait bound `u8: Trait` is not satisfied
 LL |     DictionaryLike { field: Bar<u8> },
    |                             ^^^^^^^ the trait `Trait` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums.rs:1:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/on-structs-and-enums.rs:7:12
    |
diff --git a/tests/ui/traits/deny-builtin-object-impl.current.stderr b/tests/ui/traits/deny-builtin-object-impl.current.stderr
index 5c1987426f7..8ca3d3a057f 100644
--- a/tests/ui/traits/deny-builtin-object-impl.current.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.current.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
 LL |     test_not_object::<dyn NotObject>();
    |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/deny-builtin-object-impl.rs:10:1
+   |
+LL | trait NotObject {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `test_not_object`
   --> $DIR/deny-builtin-object-impl.rs:14:23
    |
diff --git a/tests/ui/traits/deny-builtin-object-impl.next.stderr b/tests/ui/traits/deny-builtin-object-impl.next.stderr
index 5c1987426f7..8ca3d3a057f 100644
--- a/tests/ui/traits/deny-builtin-object-impl.next.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
 LL |     test_not_object::<dyn NotObject>();
    |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/deny-builtin-object-impl.rs:10:1
+   |
+LL | trait NotObject {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `test_not_object`
   --> $DIR/deny-builtin-object-impl.rs:14:23
    |
diff --git a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
index 263c59ee327..a5d0e6ab095 100644
--- a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
+++ b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
@@ -10,6 +10,11 @@ error[E0277]: the trait bound `for<'a> &'a mut Vec<&'a u32>: Foo<'static, i32>`
 LL |     <i32 as RefFoo<i32>>::ref_foo(unknown);
    |      ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-autoderef-ty-with-escaping-var.rs:3:1
+   |
+LL | trait Foo<'x, T> {}
+   | ^^^^^^^^^^^^^^^^
 note: required for `i32` to implement `RefFoo<i32>`
   --> $DIR/dont-autoderef-ty-with-escaping-var.rs:9:9
    |
diff --git a/tests/ui/traits/impl-bounds-checking.stderr b/tests/ui/traits/impl-bounds-checking.stderr
index 1f969efe114..bfa8213abe7 100644
--- a/tests/ui/traits/impl-bounds-checking.stderr
+++ b/tests/ui/traits/impl-bounds-checking.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `isize: Clone2` is not satisfied
 LL | impl Getter<isize> for isize {
    |                        ^^^^^ the trait `Clone2` is not implemented for `isize`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl-bounds-checking.rs:1:1
+   |
+LL | pub trait Clone2 {
+   | ^^^^^^^^^^^^^^^^
 note: required by a bound in `Getter`
   --> $DIR/impl-bounds-checking.rs:6:17
    |
diff --git a/tests/ui/traits/new-solver/projection-discr-kind.stderr b/tests/ui/traits/new-solver/projection-discr-kind.stderr
index 03e28f993e2..e14953f19ff 100644
--- a/tests/ui/traits/new-solver/projection-discr-kind.stderr
+++ b/tests/ui/traits/new-solver/projection-discr-kind.stderr
@@ -6,6 +6,11 @@ LL |     needs_bar(std::mem::discriminant(&x));
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-discr-kind.rs:10:1
+   |
+LL | trait Bar {}
+   | ^^^^^^^^^
 note: required by a bound in `needs_bar`
   --> $DIR/projection-discr-kind.rs:11:22
    |
diff --git a/tests/ui/traits/non_lifetime_binders/fail.stderr b/tests/ui/traits/non_lifetime_binders/fail.stderr
index 7bd02550fb3..240bcef7df5 100644
--- a/tests/ui/traits/non_lifetime_binders/fail.stderr
+++ b/tests/ui/traits/non_lifetime_binders/fail.stderr
@@ -13,6 +13,11 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
 LL |     fail();
    |     ^^^^ the trait `Trait` is not implemented for `T`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/fail.rs:6:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
 note: required by a bound in `fail`
   --> $DIR/fail.rs:10:15
    |
diff --git a/tests/ui/traits/object-does-not-impl-trait.stderr b/tests/ui/traits/object-does-not-impl-trait.stderr
index f1dd508a467..81d67255a0b 100644
--- a/tests/ui/traits/object-does-not-impl-trait.stderr
+++ b/tests/ui/traits/object-does-not-impl-trait.stderr
@@ -6,6 +6,11 @@ LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
    |                                   |
    |                                   required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-does-not-impl-trait.rs:4:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
 note: required by a bound in `take_foo`
   --> $DIR/object-does-not-impl-trait.rs:5:15
    |
diff --git a/tests/ui/traits/object/enforce-supertrait-projection.rs b/tests/ui/traits/object/enforce-supertrait-projection.rs
index 2c9b41eea2a..0ea944ec2df 100644
--- a/tests/ui/traits/object/enforce-supertrait-projection.rs
+++ b/tests/ui/traits/object/enforce-supertrait-projection.rs
@@ -7,7 +7,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
 
 fn transmute<A, B>(x: A) -> B {
     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-    //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
+    //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
 }
 
 fn foo<A, B, T: ?Sized>(x: T::A) -> B
diff --git a/tests/ui/traits/object/enforce-supertrait-projection.stderr b/tests/ui/traits/object/enforce-supertrait-projection.stderr
index 848b4e69a4b..2fb94d34896 100644
--- a/tests/ui/traits/object/enforce-supertrait-projection.stderr
+++ b/tests/ui/traits/object/enforce-supertrait-projection.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
+error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
   --> $DIR/enforce-supertrait-projection.rs:9:17
    |
 LL | fn transmute<A, B>(x: A) -> B {
diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs
new file mode 100644
index 00000000000..c6f9e345618
--- /dev/null
+++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs
@@ -0,0 +1,15 @@
+fn use_iterator<I>(itr: I)
+where
+    I: IntoIterator<Item = i32>,
+{
+}
+
+fn pass_iterator<I>(i: &dyn IntoIterator<Item = i32, IntoIter = I>)
+where
+    I: Iterator<Item = i32>,
+{
+    use_iterator(i);
+    //~^ ERROR `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator
+}
+
+fn main() {}
diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr
new file mode 100644
index 00000000000..bd0e7ca2c02
--- /dev/null
+++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr
@@ -0,0 +1,22 @@
+error[E0277]: `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator
+  --> $DIR/dont-suggest-unsize-deref.rs:11:18
+   |
+LL |     use_iterator(i);
+   |     ------------ ^ `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>`
+   = note: required for `&dyn IntoIterator<IntoIter = I, Item = i32>` to implement `IntoIterator`
+note: required by a bound in `use_iterator`
+  --> $DIR/dont-suggest-unsize-deref.rs:3:8
+   |
+LL | fn use_iterator<I>(itr: I)
+   |    ------------ required by a bound in this function
+LL | where
+LL |     I: IntoIterator<Item = i32>,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `use_iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/suggest-deferences/issue-39029.fixed b/tests/ui/traits/suggest-dereferences/issue-39029.fixed
index a1abf668b8b..a1abf668b8b 100644
--- a/tests/ui/traits/suggest-deferences/issue-39029.fixed
+++ b/tests/ui/traits/suggest-dereferences/issue-39029.fixed
diff --git a/tests/ui/traits/suggest-deferences/issue-39029.rs b/tests/ui/traits/suggest-dereferences/issue-39029.rs
index 90d097105ed..90d097105ed 100644
--- a/tests/ui/traits/suggest-deferences/issue-39029.rs
+++ b/tests/ui/traits/suggest-dereferences/issue-39029.rs
diff --git a/tests/ui/traits/suggest-deferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr
index 49105de3d69..49105de3d69 100644
--- a/tests/ui/traits/suggest-deferences/issue-39029.stderr
+++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr
diff --git a/tests/ui/traits/suggest-deferences/issue-62530.fixed b/tests/ui/traits/suggest-dereferences/issue-62530.fixed
index 406caaa007f..406caaa007f 100644
--- a/tests/ui/traits/suggest-deferences/issue-62530.fixed
+++ b/tests/ui/traits/suggest-dereferences/issue-62530.fixed
diff --git a/tests/ui/traits/suggest-deferences/issue-62530.rs b/tests/ui/traits/suggest-dereferences/issue-62530.rs
index 53846be7306..53846be7306 100644
--- a/tests/ui/traits/suggest-deferences/issue-62530.rs
+++ b/tests/ui/traits/suggest-dereferences/issue-62530.rs
diff --git a/tests/ui/traits/suggest-deferences/issue-62530.stderr b/tests/ui/traits/suggest-dereferences/issue-62530.stderr
index e47ae0b65af..e47ae0b65af 100644
--- a/tests/ui/traits/suggest-deferences/issue-62530.stderr
+++ b/tests/ui/traits/suggest-dereferences/issue-62530.stderr
diff --git a/tests/ui/traits/suggest-deferences/multiple-0.fixed b/tests/ui/traits/suggest-dereferences/multiple-0.fixed
index b7160b75c60..b7160b75c60 100644
--- a/tests/ui/traits/suggest-deferences/multiple-0.fixed
+++ b/tests/ui/traits/suggest-dereferences/multiple-0.fixed
diff --git a/tests/ui/traits/suggest-deferences/multiple-0.rs b/tests/ui/traits/suggest-dereferences/multiple-0.rs
index 9ac55177ffa..9ac55177ffa 100644
--- a/tests/ui/traits/suggest-deferences/multiple-0.rs
+++ b/tests/ui/traits/suggest-dereferences/multiple-0.rs
diff --git a/tests/ui/traits/suggest-deferences/multiple-0.stderr b/tests/ui/traits/suggest-dereferences/multiple-0.stderr
index 6a4d4b8d521..6a4d4b8d521 100644
--- a/tests/ui/traits/suggest-deferences/multiple-0.stderr
+++ b/tests/ui/traits/suggest-dereferences/multiple-0.stderr
diff --git a/tests/ui/traits/suggest-deferences/multiple-1.rs b/tests/ui/traits/suggest-dereferences/multiple-1.rs
index 91c6c7924a4..91c6c7924a4 100644
--- a/tests/ui/traits/suggest-deferences/multiple-1.rs
+++ b/tests/ui/traits/suggest-dereferences/multiple-1.rs
diff --git a/tests/ui/traits/suggest-deferences/multiple-1.stderr b/tests/ui/traits/suggest-dereferences/multiple-1.stderr
index 6e12321c233..6e12321c233 100644
--- a/tests/ui/traits/suggest-deferences/multiple-1.stderr
+++ b/tests/ui/traits/suggest-dereferences/multiple-1.stderr
diff --git a/tests/ui/traits/suggest-deferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed
index 7a8433f9057..7a8433f9057 100644
--- a/tests/ui/traits/suggest-deferences/root-obligation.fixed
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed
diff --git a/tests/ui/traits/suggest-deferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs
index 51bac2107e3..51bac2107e3 100644
--- a/tests/ui/traits/suggest-deferences/root-obligation.rs
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs
diff --git a/tests/ui/traits/suggest-deferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
index 1363fb8c47a..1363fb8c47a 100644
--- a/tests/ui/traits/suggest-deferences/root-obligation.stderr
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed
index ea3d1bf853a..ea3d1bf853a 100644
--- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed
+++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed
diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs
index 9eda68027b2..9eda68027b2 100644
--- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs
+++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs
diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr
index ede31a2c7bc..ede31a2c7bc 100644
--- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr
+++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr
diff --git a/tests/ui/traits/vtable-res-trait-param.stderr b/tests/ui/traits/vtable-res-trait-param.stderr
index 2b3e3de9b1a..4cfceefb24c 100644
--- a/tests/ui/traits/vtable-res-trait-param.stderr
+++ b/tests/ui/traits/vtable-res-trait-param.stderr
@@ -6,6 +6,11 @@ LL |     b.gimme_an_a(y)
    |       |
    |       required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/vtable-res-trait-param.rs:1:1
+   |
+LL | trait TraitA {
+   | ^^^^^^^^^^^^
 note: required by a bound in `TraitB::gimme_an_a`
   --> $DIR/vtable-res-trait-param.rs:6:21
    |
diff --git a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
index 02c5d5d2484..be472a50769 100644
--- a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
+++ b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr
@@ -27,6 +27,12 @@ LL |     Foo::test(&4i32);
    |     --------- ^^^^^ the trait `Foo` is not implemented for `i32`
    |     |
    |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/trivial-bounds-leak.rs:4:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
   --> $DIR/trivial-bounds-leak.rs:26:22
@@ -36,6 +42,11 @@ LL |     generic_function(5i32);
    |     |
    |     required by a bound introduced by this call
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/trivial-bounds-leak.rs:4:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 note: required by a bound in `generic_function`
   --> $DIR/trivial-bounds-leak.rs:29:24
    |
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
new file mode 100644
index 00000000000..eefe333da45
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
@@ -0,0 +1,25 @@
+//! This tries to prove the APIT's bounds in a canonical query,
+//! which doesn't know anything about the defining scope of either
+//! opaque type and thus makes a random choice as to which opaque type
+//! becomes the hidden type of the other. When we leave the canonical
+//! query, we attempt to actually check the defining anchor, but now we
+//! have a situation where the RPIT gets constrained outside its anchor.
+
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+type Opaque = impl Sized;
+
+fn get_rpit() -> impl Clone {}
+
+fn query(_: impl FnOnce() -> Opaque) {}
+
+fn test() -> Opaque {
+    query(get_rpit);
+    get_rpit()
+}
+
+fn main() {}
diff --git a/tests/ui/type/type-arg-out-of-scope.rs b/tests/ui/type/type-arg-out-of-scope.rs
index 02aad007707..c36f9904e5d 100644
--- a/tests/ui/type/type-arg-out-of-scope.rs
+++ b/tests/ui/type/type-arg-out-of-scope.rs
@@ -1,4 +1,4 @@
-// error-pattern:can't use generic parameters from outer function
+// error-pattern:can't use generic parameters from outer item
 fn foo<T>(x: T) {
     fn bar(f: Box<dyn FnMut(T) -> T>) { }
 }
diff --git a/tests/ui/type/type-arg-out-of-scope.stderr b/tests/ui/type/type-arg-out-of-scope.stderr
index 7f18b4510f4..8665001e243 100644
--- a/tests/ui/type/type-arg-out-of-scope.stderr
+++ b/tests/ui/type/type-arg-out-of-scope.stderr
@@ -1,22 +1,22 @@
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/type-arg-out-of-scope.rs:3:29
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |           -                 ^ use of generic parameter from outer function
+   |           -                 ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
-error[E0401]: can't use generic parameters from outer function
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/type-arg-out-of-scope.rs:3:35
    |
 LL | fn foo<T>(x: T) {
-   |        - type parameter from outer function
+   |        - type parameter from outer item
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |           -                       ^ use of generic parameter from outer function
+   |           -                       ^ use of generic parameter from outer item
    |           |
-   |           help: try using a local generic parameter instead: `<T>`
+   |           help: try introducing a local generic parameter here: `<T>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/union/projection-as-union-type-error-2.stderr b/tests/ui/union/projection-as-union-type-error-2.stderr
index bab226f271d..21f4ea103ad 100644
--- a/tests/ui/union/projection-as-union-type-error-2.stderr
+++ b/tests/ui/union/projection-as-union-type-error-2.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u8: NotImplemented` is not satisfied
 LL |     a: <Foo as Identity>::Identity,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-as-union-type-error-2.rs:9:1
+   |
+LL | trait NotImplemented {}
+   | ^^^^^^^^^^^^^^^^^^^^
 note: required for `u8` to implement `Identity`
   --> $DIR/projection-as-union-type-error-2.rs:11:25
    |
diff --git a/tests/ui/union/projection-as-union-type-error.stderr b/tests/ui/union/projection-as-union-type-error.stderr
index e4fbe9603ad..2b0241caf98 100644
--- a/tests/ui/union/projection-as-union-type-error.stderr
+++ b/tests/ui/union/projection-as-union-type-error.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `u8: Identity` is not satisfied
    |
 LL |     a:  <Foo as Identity>::Identity,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identity` is not implemented for `u8`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/projection-as-union-type-error.rs:6:1
+   |
+LL | pub trait Identity {
+   | ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs
new file mode 100644
index 00000000000..68559338d49
--- /dev/null
+++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs
@@ -0,0 +1,16 @@
+// Regression test for #115348.
+
+unsafe fn uwu() {}
+
+// Tests that the false-positive warning "unnecessary `unsafe` block"
+// should not be reported, when the error "non-exhaustive patterns"
+// appears.
+
+fn foo(x: Option<u32>) {
+    match x {
+        //~^ ERROR non-exhaustive patterns: `None` not covered
+        Some(_) => unsafe { uwu() },
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr
new file mode 100644
index 00000000000..7384899b978
--- /dev/null
+++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `None` not covered
+  --> $DIR/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs:10:11
+   |
+LL |     match x {
+   |           ^ pattern `None` not covered
+   |
+note: `Option<u32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+  ::: $SRC_DIR/core/src/option.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Option<u32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Some(_) => unsafe { uwu() },
+LL ~         None => todo!(),
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/unsized/issue-115203.rs b/tests/ui/unsized/issue-115203.rs
new file mode 100644
index 00000000000..5fe7bd64288
--- /dev/null
+++ b/tests/ui/unsized/issue-115203.rs
@@ -0,0 +1,11 @@
+// compile-flags: --emit link
+
+fn main() {
+    let a: [i32; 0] = [];
+    match [a[..]] {
+        //~^ ERROR cannot move a value of type `[i32]
+        //~| ERROR cannot move out of type `[i32]`, a non-copy slice
+        [[]] => (),
+        _ => (),
+    }
+}
diff --git a/tests/ui/unsized/issue-115203.stderr b/tests/ui/unsized/issue-115203.stderr
new file mode 100644
index 00000000000..3ee734988c5
--- /dev/null
+++ b/tests/ui/unsized/issue-115203.stderr
@@ -0,0 +1,19 @@
+error[E0161]: cannot move a value of type `[i32]`
+  --> $DIR/issue-115203.rs:5:12
+   |
+LL |     match [a[..]] {
+   |            ^^^^^ the size of `[i32]` cannot be statically determined
+
+error[E0508]: cannot move out of type `[i32]`, a non-copy slice
+  --> $DIR/issue-115203.rs:5:12
+   |
+LL |     match [a[..]] {
+   |            ^^^^^
+   |            |
+   |            cannot move out of here
+   |            move occurs because value has type `[i32]`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0161, E0508.
+For more information about an error, try `rustc --explain E0161`.
diff --git a/tests/ui/unsized/issue-75707.stderr b/tests/ui/unsized/issue-75707.stderr
index 97618ed05ed..aa7f9c78fa8 100644
--- a/tests/ui/unsized/issue-75707.stderr
+++ b/tests/ui/unsized/issue-75707.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `MyCall: Callback` is not satisfied
 LL |     f::<dyn Processing<Call = MyCall>>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Callback` is not implemented for `MyCall`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-75707.rs:1:1
+   |
+LL | pub trait Callback {
+   | ^^^^^^^^^^^^^^^^^^
 note: required by a bound in `f`
   --> $DIR/issue-75707.rs:9:9
    |
diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr
index 9fd0f9c81eb..21122e37da5 100644
--- a/tests/ui/wf/hir-wf-canonicalized.stderr
+++ b/tests/ui/wf/hir-wf-canonicalized.stderr
@@ -3,12 +3,24 @@ error[E0277]: the trait bound `Bar<'a, T>: Foo` is not satisfied
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<'a, T>`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/hir-wf-canonicalized.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
   --> $DIR/hir-wf-canonicalized.rs:10:15
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/hir-wf-canonicalized.rs:3:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 
 error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
   --> $DIR/hir-wf-canonicalized.rs:10:15
diff --git a/tests/ui/wf/issue-95665.stderr b/tests/ui/wf/issue-95665.stderr
index b1cda59a916..f80cd41a4c2 100644
--- a/tests/ui/wf/issue-95665.stderr
+++ b/tests/ui/wf/issue-95665.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `u8: Trait` is not satisfied
 LL |     static VAR: Struct<u8>;
    |                 ^^^^^^^^^^ the trait `Trait` is not implemented for `u8`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-95665.rs:4:1
+   |
+LL | pub trait Trait: {}
+   | ^^^^^^^^^^^^^^^
 note: required by a bound in `Struct`
   --> $DIR/issue-95665.rs:6:22
    |
diff --git a/tests/ui/wf/wf-complex-assoc-type.stderr b/tests/ui/wf/wf-complex-assoc-type.stderr
index ef613e3132d..6a623bec815 100644
--- a/tests/ui/wf/wf-complex-assoc-type.stderr
+++ b/tests/ui/wf/wf-complex-assoc-type.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `bool: MyTrait` is not satisfied
 LL |     type MyItem = Option<((AssertMyTrait<bool>, u8))>;
    |                            ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `bool`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-complex-assoc-type.rs:1:1
+   |
+LL | trait MyTrait {}
+   | ^^^^^^^^^^^^^
 note: required by a bound in `AssertMyTrait`
   --> $DIR/wf-complex-assoc-type.rs:2:25
    |
diff --git a/tests/ui/wf/wf-foreign-fn-decl-ret.stderr b/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
index b03023b5fd1..0e93601043a 100644
--- a/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
+++ b/tests/ui/wf/wf-foreign-fn-decl-ret.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
    |
 LL |     pub fn lint_me() -> <() as Foo>::Assoc;
    |                         ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-foreign-fn-decl-ret.rs:6:1
+   |
+LL | pub trait Foo {
+   | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
   --> $DIR/wf-foreign-fn-decl-ret.rs:14:32
@@ -10,6 +16,11 @@ error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
 LL |     pub fn lint_me_aswell() -> Bar<u32>;
    |                                ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-foreign-fn-decl-ret.rs:1:1
+   |
+LL | pub trait Unsatisfied {}
+   | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `Bar`
   --> $DIR/wf-foreign-fn-decl-ret.rs:4:19
    |
diff --git a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
index e460cdcd3f3..52f46562c37 100644
--- a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
+++ b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr
@@ -3,6 +3,12 @@ error[E0277]: the trait bound `DefaultAllocator: Allocator` is not satisfied
    |
 LL | struct Foo(Matrix<<DefaultAllocator as Allocator>::Buffer>);
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `DefaultAllocator`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:23:1
+   |
+LL | pub trait Allocator { type Buffer; }
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
index 191a8ca8ebc..29b36f44a4d 100644
--- a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
+++ b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied
 LL |     called()
    |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&'b ())`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/higher-ranked-fn-type.rs:6:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
    |
diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
index ce409f627be..54afeaa7eda 100644
--- a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
+++ b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_t
 LL |     called()
    |     ^^^^^^ the trait `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b))> Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ())`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/higher-ranked-fn-type.rs:6:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
    |
diff --git a/tests/ui/where-clauses/where-clause-method-substituion.stderr b/tests/ui/where-clauses/where-clause-method-substituion.stderr
index 8c47ed6d431..2f3b615a13b 100644
--- a/tests/ui/where-clauses/where-clause-method-substituion.stderr
+++ b/tests/ui/where-clauses/where-clause-method-substituion.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `X: Foo<X>` is not satisfied
 LL |     1.method::<X>();
    |                ^ the trait `Foo<X>` is not implemented for `X`
    |
+help: this trait has no implementations, consider adding one
+  --> $DIR/where-clause-method-substituion.rs:1:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
 note: required by a bound in `Bar::method`
   --> $DIR/where-clause-method-substituion.rs:6:34
    |